Example #1
0
def loadFormationSelectionFrame(manager):
    """Loads all formations files in the same directory as this .py file and builds a UI element with buttons for each formation.
        Formations are .csv files where the nth line is the x, y, z coordinate of the nth drone."""
    manager = manager

    formations = [
    ]  # a list of formations, which are lists consisting of the name and the positions as a numpy array
    # load all .txt files in the formations folder
    directory = os.path.dirname(
        os.path.abspath(__file__)
    )  # the directory this.py file is in, which also contains the formation files
    for file in os.listdir(directory):
        if file.endswith(".csv"):
            path = os.path.join(directory, file)
            formations.append(_loadFormation(path))

    # size and position of the buttons and the scrollable frame
    buttonSize = (-8, 8, -.2, .8)
    buttonDistance = 0.15
    scrolledFrame = DirectScrolledFrame(frameColor=(.2, .2, .2, 1),
                                        canvasSize=(-.7, .7, -buttonDistance *
                                                    len(formations), 0),
                                        frameSize=(-.9, .9, -.5, .5),
                                        pos=(.8, 0, -.7),
                                        scale=.5)
    canvas = scrolledFrame.getCanvas()

    # add a button for each formation
    for i in range(0, len(formations)):
        button = DirectButton(text=formations[i][0],
                              scale=.1,
                              frameSize=buttonSize,
                              command=manager.applyFormation,
                              extraArgs=[formations[i]])
        button.reparentTo(canvas)
        button.setPos(0.15, 0, -(i + 0.75) * buttonDistance)

    print("{} formations loaded.".format(len(formations)))
Example #2
0
class DirectWindow( DirectFrame ):
  def __init__( self,
                pos              = ( -.5, .5),
                title            = 'Title',
                curSize          = ( 1, 1),
                maxSize          = ( 1, 1 ),
                minSize          = ( .5, .5 ),
                backgroundColor  = ( 1, 1, 1, 1 ),
                borderColor      = ( 1, 1, 1, 1 ),
                titleColor       = ( 1, 1, 1, 1 ),
                borderSize       = 0.04,
                titleSize        = 0.06,
                closeButton      = False,
                windowParent     = aspect2d,
                preserve         = True,
                preserveWhole      = True,
              ):
    self.preserve = preserve
    self.preserveWhole = preserveWhole
    self.windowParent = windowParent
    self.windowPos = pos
    DirectFrame.__init__( self,
        parent       = windowParent,
        pos          = ( self.windowPos[0], 0, self.windowPos[1] ),
        frameColor  = ( 0, 0, 0, 0 ),
        frameTexture = loader.loadTexture( DIRECTORY+'transparent.png' )
      )
    self.setTransparency(True)
   
    # the title part of the window, drag around to move the window
    self.headerHeight = titleSize
    h = -self.headerHeight
    self.windowHeaderLeft = DirectButton(
        parent       = self,
        frameTexture = DEFAULT_TITLE_GEOM_LEFT,
        frameSize    = ( -.5, .5, -.5, .5 ),
        borderWidth  = ( 0, 0 ),
        relief       = DGG.FLAT,
        frameColor   = titleColor,
      )
    self.windowHeaderCenter = DirectButton(
        parent       = self,
        frameTexture = DEFAULT_TITLE_GEOM_CENTER,
        frameSize    = ( -.5, .5, -.5, .5 ),
        borderWidth  = ( 0, 0 ),
        relief       = DGG.FLAT,
        frameColor   = titleColor,
      )
    if closeButton:
      rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT_CLOSE
      command = self.destroy
    else:
      rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT
      command = None
    self.windowHeaderRight = DirectButton(
        parent       = self,
        frameTexture = rightTitleGeom,
        frameSize    = ( -.5, .5, -.5, .5 ),
        borderWidth  = ( 0, 0 ),
        relief       = DGG.FLAT,
        frameColor   = titleColor,
        command      = command
      )
   
    self.windowHeaderLeft.setTransparency(True)
    self.windowHeaderCenter.setTransparency(True)
    self.windowHeaderRight.setTransparency(True)
   
    self.windowHeaderLeft.bind( DGG.B1PRESS, self.startWindowDrag )
    self.windowHeaderCenter.bind( DGG.B1PRESS, self.startWindowDrag )
    self.windowHeaderRight.bind( DGG.B1PRESS, self.startWindowDrag )
   
    # this is not handled correctly, if a window is dragged which has been
    # created before another it will not be released
    # check the bugfixed startWindowDrag function
    #self.windowHeader.bind(DGG.B1RELEASE,self.stopWindowDrag)
   
    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.attachNewNode(text)
    self.textNodePath.setScale(self.headerHeight*0.8)
   
    # the content part of the window, put stuff beneath
    # contentWindow.getCanvas() to put it into it
    self.maxVirtualSize = maxSize
    self.minVirtualSize = minSize
    self.resizeSize     = borderSize
    self.contentWindow = DirectScrolledFrame(
        parent                                  = self,
        pos                                     = ( 0, 0, -self.headerHeight ),
        canvasSize                              = ( 0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1] ),
        frameColor                              = ( 0, 0, 0, 0), # defines the background color of the resize-button
        relief                                  = DGG.FLAT,
        borderWidth                             = (0, 0),
        verticalScroll_frameSize                = [0, self.resizeSize, 0, 1],
        horizontalScroll_frameSize              = [0, 1, 0, self.resizeSize],
       
        # resize the scrollbar according to window size
        verticalScroll_resizeThumb              = False,
        horizontalScroll_resizeThumb            = False,
        # define the textures for the scrollbars
        verticalScroll_frameTexture             = VERTICALSCROLL_FRAMETEXTURE,
        verticalScroll_incButton_frameTexture   = VERTICALSCROLL_INCBUTTON_FRAMETEXTURE,
        verticalScroll_decButton_frameTexture   = VERTICALSCROLL_DECBUTTON_FRAMETEXTURE,
        verticalScroll_thumb_frameTexture       = VERTICALSCROLL_TUMB_FRAMETEXTURE,
        horizontalScroll_frameTexture           = HORIZONTALSCROLL_FRAMETEXTURE,
        horizontalScroll_incButton_frameTexture = HORIZONTALSCROLL_INCBUTTON_FRAMETEXTURE,
        horizontalScroll_decButton_frameTexture = HORIZONTALSCROLL_DECBUTTON_FRAMETEXTURE,
        horizontalScroll_thumb_frameTexture     = HORIZONTALSCROLL_TUMB_FRAMETEXTURE,
        # make all flat, so the texture is as we want it
        verticalScroll_relief                   = DGG.FLAT,
        verticalScroll_thumb_relief             = DGG.FLAT,
        verticalScroll_decButton_relief         = DGG.FLAT,
        verticalScroll_incButton_relief         = DGG.FLAT,
        horizontalScroll_relief                 = DGG.FLAT,
        horizontalScroll_thumb_relief           = DGG.FLAT,
        horizontalScroll_decButton_relief       = DGG.FLAT,
        horizontalScroll_incButton_relief       = DGG.FLAT,
        # colors
        verticalScroll_frameColor               = borderColor,
        verticalScroll_incButton_frameColor     = borderColor,
        verticalScroll_decButton_frameColor     = borderColor,
        verticalScroll_thumb_frameColor         = borderColor,
        horizontalScroll_frameColor             = borderColor,
        horizontalScroll_incButton_frameColor   = borderColor,
        horizontalScroll_decButton_frameColor   = borderColor,
        horizontalScroll_thumb_frameColor       = borderColor,
      )
    self.contentWindow.setTransparency(True)


    # background color
    self.backgroundColor = DirectFrame(
        parent       = self.contentWindow.getCanvas(),
        frameSize    = ( 0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1] ),
        frameColor   = backgroundColor,
        relief       = DGG.FLAT,
        borderWidth  = ( .01, .01),
      )
    self.backgroundColor.setTransparency(True)

    # Add a box
    self.box = boxes.VBox(parent = self.getCanvas())

   
    # is needed for some nicer visuals of the resize button (background)
    self.windowResizeBackground = DirectButton(
        parent       = self,
        frameSize    = ( -.5, .5, -.5, .5 ),
        borderWidth  = ( 0, 0 ),
        scale        = ( self.resizeSize, 1, self.resizeSize ),
        relief       = DGG.FLAT,
        frameColor   = backgroundColor,
      )

    # the resize button of the window
    self.windowResize = DirectButton(
        parent       = self,
        frameSize    = ( -.5, .5, -.5, .5 ),
        borderWidth  = ( 0, 0 ),
        scale        = ( self.resizeSize, 1, self.resizeSize ),
        relief       = DGG.FLAT,
        frameTexture = DEFAULT_RESIZE_GEOM,
        frameColor   = borderColor,
      )
    self.windowResize.setTransparency(True)
    self.windowResize.bind(DGG.B1PRESS,self.startResizeDrag)
    self.windowResize.bind(DGG.B1RELEASE,self.stopResizeDrag)
   
    # offset then clicking on the resize button from the mouse to the resizebutton
    # position, required to calculate the position / scaling
    self.offset = None
    self.taskName = "resizeTask-%s" % str(hash(self))
   
    # do sizing of the window (minimum)
    #self.resize( Vec3(0,0,0), Vec3(0,0,0) )
    # maximum
    #self.resize( Vec3(100,0,-100), Vec3(0,0,0) )
    self.resize( Vec3(curSize[0], 0, -curSize[1]), Vec3(0,0,0))
 
  def getCanvas(self):
    return self.contentWindow.getCanvas()
 
  # dragging functions
  def startWindowDrag( self, param ):
    self.wrtReparentTo( aspect2dMouseNode )
    self.ignoreAll()
    self.accept( 'mouse1-up', self.stopWindowDrag )
  def stopWindowDrag( self, param=None ):
    # this is called 2 times (bug), so make sure it's not already parented to aspect2d
    if self.getParent() != self.windowParent:
      self.wrtReparentTo( self.windowParent )
    if self.preserve:
        if self.preserveWhole:
            if self.getZ() > 1:
                self.setZ(1)
            elif self.getZ() < -1 - self.getHeight():
                self.setZ(-1 - self.getHeight())
            if self.getX() > base.a2dRight - self.getWidth():
                self.setX(base.a2dRight - self.getWidth())
            elif self.getX() < base.a2dLeft:
                self.setX(base.a2dLeft)
        else:
            if self.getZ() > 1:
                self.setZ(1)
            elif self.getZ() < -1 + self.headerHeight:
                self.setZ(-1 + self.headerHeight)
            if self.getX() > base.a2dRight - self.headerHeight:
                self.setX(base.a2dRight - self.headerHeight)
            elif self.getX() < base.a2dLeft + self.headerHeight - self.getWidth():
                self.setX(base.a2dLeft + self.headerHeight - self.getWidth())
    #else: #Window moved beyond reach. Destroy window?
  # resize functions
  def resize( self, mPos, offset ):
    mXPos = max( min( mPos.getX(), self.maxVirtualSize[0] ), self.minVirtualSize[0])
    mZPos = max( min( mPos.getZ(), -self.minVirtualSize[1] ), -self.maxVirtualSize[1]-self.headerHeight)
    self.windowResize.setPos( mXPos-self.resizeSize/2., 0, mZPos+self.resizeSize/2. )
    self.windowResizeBackground.setPos( mXPos-self.resizeSize/2., 0, mZPos+self.resizeSize/2. )
    self['frameSize'] = (0, mXPos, 0, mZPos)
    self.windowHeaderLeft.setPos( self.headerHeight/2., 0, -self.headerHeight/2. )
    self.windowHeaderLeft.setScale( self.headerHeight, 1, self.headerHeight )
    self.windowHeaderCenter.setPos( mXPos/2., 0, -self.headerHeight/2. )
    self.windowHeaderCenter.setScale( mXPos - self.headerHeight*2., 1, self.headerHeight )
    self.windowHeaderRight.setPos( mXPos-self.headerHeight/2., 0, -self.headerHeight/2. )
    self.windowHeaderRight.setScale( self.headerHeight, 1, self.headerHeight )
    self.contentWindow['frameSize'] = ( 0, mXPos, mZPos+self.headerHeight, 0)
    self.textNodePath.setPos( mXPos/2., 0, -self.headerHeight/3.*2. )
    # show and hide that small background for the window sizer
    if mXPos == self.maxVirtualSize[0] and \
       mZPos == -self.maxVirtualSize[1]-self.headerHeight:
      self.windowResizeBackground.hide()
    else:
      self.windowResizeBackground.show()
 
  def resizeTask( self, task=None ):
    mPos = aspect2dMouseNode.getPos( self )+self.offset
    self.resize( mPos, self.offset )
    return task.cont
  def startResizeDrag( self, param ):
    self.offset  = self.windowResize.getPos( aspect2dMouseNode )
    taskMgr.remove( self.taskName )
    taskMgr.add( self.resizeTask, self.taskName )
  def stopResizeDrag( self, param ):
    taskMgr.remove( self.taskName )
    # get the window to the front
    self.wrtReparentTo( self.windowParent )
  def addHorizontal(self, widgets):
      """
      Accepts a list of directgui objects which are added to a horizontal box, which is then added to the vertical stack.
      """
      hbox = boxes.HBox()
      for widget in widgets:
          hbox.pack(widget)
      self.box.pack(hbox)
      self.updateMaxSize()
 
  def addVertical(self, widgets):
      """
      Accepts a list of directgui objects which are added to a vertical box, which is then added to the vertical stack.
      May cause funky layout results.
      """
      #vbox = boxes.VBox()
      for widget in widgets:
          self.box.pack(widget)
      self.updateMaxSize()
 
  def add(self, widgets):
      """Shortcut function for addVertical"""
      self.addVertical(widgets)
 
  def updateMaxSize(self):
      """Updates the max canvas size to include all items packed.
      Window is resized to show all contents."""
      bottomLeft, topRight = self.box.getTightBounds()
      self.maxVirtualSize = (topRight[0], -bottomLeft[2])
      self.contentWindow['canvasSize'] = ( 0, self.maxVirtualSize[0], -self.maxVirtualSize[1],  0)
      self.backgroundColor['frameSize'] = ( 0, self.maxVirtualSize[0], -self.maxVirtualSize[1], 0 )

      #perhaps this should be optional -- automatically resize for new elements
      self.reset()
 
  def reset(self):
    """Poorly named function that resizes window to fit all contents"""
    self.resize( Vec3(self.maxVirtualSize[0], 0, -self.maxVirtualSize[1]-self.headerHeight), Vec3(0,0,0))
class TextScrolledFrame(object):
    def __init__(self, parent=None, scale=0.05, limitText=1, frameSize=(0, 1.3, 0.2, 0.697), pos=(0, 0, 0.1)):

        self.__scale = scale
        self.__frameSize = frameSize
        self.__canvasSize = (frameSize[0], frameSize[2] - 0.01, frameSize[2], frameSize[3])
        self.__limitText = limitText
        self.__countLine = []

        self.dsf = DirectScrolledFrame(
            parent=parent,
            canvasSize=self.__canvasSize,
            frameSize=self.__frameSize,
            pos=pos,
            frameColor=COR_OPACITY_03_PRETO,
            autoHideScrollBars=1,
            scrollBarWidth=0.05,
            borderWidth=(0, 0),
            verticalScroll_value=1,
            verticalScroll_decButton_frameColor=(1, 1, 1, 0.3),
            verticalScroll_decButton_rolloverSound=None,
            verticalScroll_decButton_clickSound=None,
            verticalScroll_incButton_frameColor=(1, 1, 1, 0.3),
            verticalScroll_incButton_rolloverSound=None,
            verticalScroll_incButton_clickSound=None,
            verticalScroll_thumb_frameColor=(1, 1, 1, 0.3),
            verticalScroll_thumb_rolloverSound=None,
            verticalScroll_thumb_clickSound=None,
        )

        self.__textoHeight = scale
        self.__canvasHeight = self.dsf.getHeight()
        self.__canvas = self.dsf.getCanvas()

    def __command_clear_msg(self):
        self.etyMsg.set("")

    def __reposicionaTexto(self, obj_text):
        height = obj_text.getScale() * obj_text.textNode.getNumRows()

        for text in self.__countLine:
            lastPos = text.textNodePath.getPos()
            text.setPos((lastPos[0], 0, lastPos[2] + height))

    def __resizeCanvasSize(self, text):

        self.__textoHeight += text.getScale() * text.textNode.getNumRows()

        if self.__textoHeight > self.__canvasHeight:
            self.__canvasHeight += self.__textoHeight - self.__canvasHeight

        self.dsf["canvasSize"] = (
            self.dsf["canvasSize"][0],
            self.dsf["canvasSize"][1],
            self.dsf["canvasSize"][2],
            self.dsf["canvasSize"][2] + self.__canvasHeight,
        )
        self.dsf.setCanvasSize()

    def show(self, texto, cor=(1, 1, 1, 1)):

        dfs_pos = self.dsf.getPos()

        pos = (dfs_pos[0] + 0.01, 0, dfs_pos[1] + 0.16)

        text = Text(parent=self.__canvas, scale=self.__scale, text=texto, wordwrap=25, pos=pos, cor=cor)

        numText = len(self.__countLine)
        if numText > 0:
            self.__reposicionaTexto(text)

        self.__countLine.append(text)

        if numText > self.__limitText:
            self.__countLine[0].remove()
            self.__countLine.pop(0)
        else:
            self.__resizeCanvasSize(text)

        self.dsf["verticalScroll_value"] = 1
Example #4
0
class TabbedFrame(DirectFrame):
    def __init__(self, parent=None, **kwargs):
        optiondefs = (
            ('frameSize', (-0.5, 0.5, -0.5, 0.5), None),
            ('tabClickOffsetColor', Vec4(0.1, 0.1, 0.1, 0), None),
            ('tabRolloverOffsetColor', Vec4(0.1, 0.1, 0.1, 0), None),
            ('tabInactiveColor', Vec4(0.2, 0.2, 0.2, 1), None),
            ('tabUnselectedColor', Vec4(0.7, 0.7, 0.7, 1), None),
            ('tabSelectedColor', Vec4(0.4, 0.7, 1.0, 1), None),
            ('tab_scale', 0.05, None),
            ('tab_frameSize', (0, 5, 0, 2), None),
            ('tab_geom_scale', 1, None),
            ('tabHighlightFrameTexture', None, None),
            ('tabFrameTexture', None, None),
            ('tabHighlightGeom', None, None),
            ('tabGeom', None, None),
        )

        # Button colours: Selected, unselected, rollover-offset, clicked-offset, inactive
        if "scrollFrameConstructor" in kwargs:
            self.scrollFrameConstructor = kwargs["scrollFrameConstructor"]
            del kwargs["scrollFrameConstructor"]
        else:
            self.scrollFrameConstructor = None  #type(DirectScrolledFrame)
        if "pageChangeCallback" in kwargs:
            self.pageChangeCallback = kwargs["pageChangeCallback"]
            del kwargs["pageChangeCallback"]
        else:
            self.pageChangeCallback = None  #type(DirectScrolledFrame)

        viewingArgs = {}
        for key, arg in list(kwargs.items()):
            if key.startswith("scroll_"):
                key = key[7:]
                viewingArgs[key] = arg
        for key in viewingArgs:
            del kwargs["scroll_" + key]

        if not "canvasSize" in viewingArgs:
            viewingArgs["canvasSize"] = (0, 0, 0, 0)

        self.defineoptions(kwargs, optiondefs)

        DirectFrame.__init__(self, parent)

        if self.scrollFrameConstructor is not None:
            self.viewingArea = self.scrollFrameConstructor(parent=self,
                                                           **viewingArgs)
        else:
            self.viewingArea = DirectScrolledFrame(parent=self, **viewingArgs)

        self.pages = []
        self.pageButtons = []

        self.currentPageIndex = -1

        self.tabArgs = {}
        for key, arg in self._constructorKeywords.items():
            if key.startswith("tab_") and \
                        not key.endswith("highlightGeom") and \
                        not key.endswith("unselectedColor") and \
                        not key.endswith("selectedColor") and \
                        not key.endswith("highlightFrameTexture") and \
                        not key.endswith("highlightGeom"):
                self.tabArgs[key[4:]] = arg[0]

        self.addPage(DirectFrame(), "<stand-in>")

        self.initialiseoptions(TabbedFrame)

    def __setitem__(self, key, value):
        DirectFrame.__setitem__(self, key, value)
        if key.startswith("tab_"):
            self.tabArgs[key[4:]] = value

    def addPage(self,
                page,
                pageName,
                selectedCallback=None,
                deselectedCallback=None,
                callbackArg=None):
        if len(self.pages) > 0 and self.pageButtons[0]["text"] == "<stand-in>":
            self.pageButtons[0].destroy()
            self.pageButtons = []
            self.pages[0][0].destroy()
            self.pages = []

        btn = self.makeButton(pageName, len(self.pages))

        self.pageButtons.append(btn)

        self.dehighlightButton(-1)

        self.pages.append(
            (page, selectedCallback, deselectedCallback, callbackArg))

        page.hide()
        page.detachNode()

        self.layoutButtons()

        if len(self.pages) == 1:
            self.currentPageIndex = -1
            self.setPage(0)

    def makeButton(self, pageName, pageIndex):
        btn = self.createcomponent("tab%d" % len(self.pageButtons), (),
                                   "tab",
                                   DirectButton, (self, ),
                                   command=self.setPage,
                                   text=pageName,
                                   extraArgs=[pageIndex],
                                   **self.tabArgs)

        return btn

    def highlightButton(self, index):
        if index >= -len(self.pageButtons) and index < len(self.pageButtons):
            btn = self.pageButtons[index]

            if self["tabHighlightGeom"] is not None:
                btn["geom"] = self["tabHighlightGeom"]

            if self["tabHighlightFrameTexture"] is not None:
                btn["frameTexture"] = self["tabHighlightFrameTexture"]

            btn["frameColor"] = (self["tabSelectedColor"],
                                 self["tabSelectedColor"],
                                 self["tabSelectedColor"],
                                 self["tabInactiveColor"])

    def dehighlightButton(self, index):
        if index >= -len(self.pageButtons) and index < len(self.pageButtons):
            btn = self.pageButtons[index]

            if self["tabGeom"] is not None:
                btn["geom"] = self["tabGeom"]

            if self["tabFrameTexture"] is not None:
                btn["frameTexture"] = self["tabFrameTexture"]

            btn["frameColor"] = (self["tabUnselectedColor"],
                                 self["tabUnselectedColor"] +
                                 self["tabClickOffsetColor"],
                                 self["tabUnselectedColor"] +
                                 self["tabRolloverOffsetColor"],
                                 self["tabInactiveColor"])

    def setPage(self, index):
        if index == self.currentPageIndex:
            return

        if self.currentPageIndex >= 0:
            page, selectedCallback, deselectedCallback, callbackArg = self.pages[
                self.currentPageIndex]
            page.hide()
            page.detachNode()
            self.dehighlightButton(self.currentPageIndex)
            if deselectedCallback is not None:
                deselectedCallback(callbackArg)

        if index >= 0 and index < len(self.pages):
            newPage, selectedCallback, deselectedCallback, callbackArg = self.pages[
                index]
            newPage.show()
            newPage.reparentTo(self.viewingArea.getCanvas())
            if selectedCallback is not None:
                selectedCallback(callbackArg)

            self.layoutPage(newPage)

            self.highlightButton(index)

        self.currentPageIndex = index

        if self.pageChangeCallback is not None:
            self.pageChangeCallback(self)

    def nextPage(self):
        if self.currentPageIndex < len(self.pages) - 1:
            self.setPage(self.currentPageIndex + 1)

    def previousPage(self):
        if self.currentPageIndex > 0:
            self.setPage(self.currentPageIndex - 1)

    def layoutPage(self, page):
        pageBounds = page["frameSize"]
        if pageBounds is None:
            pageBounds = tuple(self.viewingArea["frameSize"])
        mainBounds = self.viewingArea["frameSize"]

        tall = False
        if pageBounds[2] < mainBounds[2]:
            tall = True
            b = pageBounds[2] - 0.15
        else:
            b = mainBounds[2]
        if pageBounds[3] > mainBounds[3]:
            tall = True
            t = pageBounds[3]
        else:
            t = mainBounds[3]
        if pageBounds[0] < mainBounds[0]:
            l = pageBounds[0]
        else:
            l = mainBounds[0]
        if tall or pageBounds[1] > mainBounds[1]:
            r = pageBounds[1]
        else:
            r = mainBounds[1]

        self.viewingArea["canvasSize"] = (l, r, b, t)

    def layoutButtons(self):
        width = self["tab_frameSize"][1] - self["tab_frameSize"][0]
        buttonScale = self["tab_scale"]
        if isinstance(buttonScale, tuple) or isinstance(buttonScale, list) or \
                isinstance(buttonScale, VBase3) or hasattr(buttonScale, "__getitem__"):
            buttonScale = buttonScale[0]

        for pageIndex, button in enumerate(self.pageButtons):
            bounds = self["frameSize"]
            pos = (bounds[0] + pageIndex * width * buttonScale, 0, bounds[3])
            button.setPos(*pos)

    def setFrameSize(self, fClearFrame=0):
        self.layoutButtons()

        DirectFrame.setFrameSize(self, fClearFrame)
        self.viewingArea["frameSize"] = self["frameSize"]

        self.layoutPage(self.pages[self.currentPageIndex][0])

    def clearPages(self):
        for btn in self.pageButtons:
            btn.destroy()
        for page, callback1, callback2, arg in self.pages:
            page.destroy()

        self.currentdeselectedCallback = None

        self.pageButtons = []
        self.pages = []

        self.currentPageIndex = -1

    def destroy(self):
        self.clearPages()

        DirectFrame.destroy(self)
	def create_leaderboard(self,level):
		# Direct frame to hold all contents of the leaderboard
		self.leaderboard_frame = DirectFrame(parent=self.main_frame,frameColor = (.8,.8,.8,.9),frameSize=(-2,2,-1,1), pos=(0,0,0))

		# Create a scroll_frame to hold contents of leaderboard file
		scroll_frame = DirectScrolledFrame(parent = self.leaderboard_frame,
						   canvasSize=(-1,1,-4,4),
					           frameColor = (1,1,1,.9),
						   frameSize=(-1,1,-.5,.5), 
						   pos=(0,0,0),
						   manageScrollBars=True,
						   scrollBarWidth = .04, 
					           autoHideScrollBars = True)

		# Frame title
		title = OnscreenText(parent=self.leaderboard_frame, text = 'LEADERBOARD', pos = (0, .6), scale = 0.15, fg=(0,.2,.2,1),shadow=(.5,.5,.5,1))
		
		# Open .leaderboard.txt file as read only
		leaderboard_file = open('files/.leaderboard.txt','r')
		start_read = False					# Boolean that will used to notify loop when to start generating text on the scroll canvas
		start = leaderboard_file.read(1)			# Reads only the first byte of the file, equivalent to a character

		# Guide for leaderboard
		name = OnscreenText(parent=scroll_frame.getCanvas(), text = 'NAME', pos = (-.1, 3.9), scale = 0.075,fg=(0,.2,.2,1))
		score = OnscreenText(parent=scroll_frame.getCanvas(), text = 'SCORE', pos = (.5, 3.9), scale = 0.075,fg=(0,.2,.2,1))
		
		index = 1
		v_pos = 3.8

		# Loop will iterate through the contents of the file
		while len(start) != 0:
			if start == '#': leaderboard_file.readline()			# Comments in text file start with an octothorpe and are ignored
			elif start == '@'and start_read is False:			# Line with @ signify the beginning of a set of level info
				if leaderboard_file.readline().split()[0] == level:	# This checks if the info that follows is the information we need
					start_read = True
			elif start == '@'and start_read is True:			# If this condition is true then we read through all the information we need
				break
			elif start_read is True:
				coord = leaderboard_file.readline().split(',')
				if len(coord) == 1:
					name = 'Unknown'				
					score = coord[0]
				else:
					name = start + coord[0]					
					score = coord[1]					
				entry_text = str(index) + ".\t " + name + '\t\t' + score
				# Create onscreen text for each entry
				entry = OnscreenText(parent=scroll_frame.getCanvas(), text = entry_text, pos = (0,v_pos), scale = 0.07,fg=(0,0,0,1))
				# Increase index and decrease vertical position
				index += 1
				v_pos -= .1
			# Read the first byte of the next line
			start = leaderboard_file.read(1)

		leaderboard_file.close()

		# Create button to go back to the leaderboard selection frame
		self.create_menu_button(self.leaderboard_frame,'Back',LVecBase3f(0,0,-.7),self.show_lb_selection)

		# Hide frame
		self.leaderboard_frame.hide()
Example #6
0
class DirectWindow(DirectFrame):
    def __init__(
        self,
        pos=(-.5, .5),
        title='Title',
        curSize=(1, 1),
        maxSize=(1, 1),
        minSize=(.5, .5),
        backgroundColor=(1, 1, 1, 1),
        borderColor=(1, 1, 1, 1),
        titleColor=(1, 1, 1, 1),
        borderSize=0.04,
        titleSize=0.06,
        closeButton=False,
        windowParent=aspect2d,
        preserve=True,
        preserveWhole=True,
    ):
        self.preserve = preserve
        self.preserveWhole = preserveWhole
        self.windowParent = windowParent
        self.windowPos = pos
        DirectFrame.__init__(
            self,
            parent=windowParent,
            pos=(self.windowPos[0], 0, self.windowPos[1]),
            frameColor=(0, 0, 0, 0),
            frameTexture=loader.loadTexture(DIRECTORY + 'transparent.png'))
        self.setTransparency(True)

        # the title part of the window, drag around to move the window
        self.headerHeight = titleSize
        h = -self.headerHeight
        self.windowHeaderLeft = DirectButton(
            parent=self,
            frameTexture=DEFAULT_TITLE_GEOM_LEFT,
            frameSize=(-.5, .5, -.5, .5),
            borderWidth=(0, 0),
            relief=DGG.FLAT,
            frameColor=titleColor,
        )
        self.windowHeaderCenter = DirectButton(
            parent=self,
            frameTexture=DEFAULT_TITLE_GEOM_CENTER,
            frameSize=(-.5, .5, -.5, .5),
            borderWidth=(0, 0),
            relief=DGG.FLAT,
            frameColor=titleColor,
        )
        if closeButton:
            rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT_CLOSE
            command = self.destroy
        else:
            rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT
            command = None
        self.windowHeaderRight = DirectButton(parent=self,
                                              frameTexture=rightTitleGeom,
                                              frameSize=(-.5, .5, -.5, .5),
                                              borderWidth=(0, 0),
                                              relief=DGG.FLAT,
                                              frameColor=titleColor,
                                              command=command)

        self.windowHeaderLeft.setTransparency(True)
        self.windowHeaderCenter.setTransparency(True)
        self.windowHeaderRight.setTransparency(True)

        self.windowHeaderLeft.bind(DGG.B1PRESS, self.startWindowDrag)
        self.windowHeaderCenter.bind(DGG.B1PRESS, self.startWindowDrag)
        self.windowHeaderRight.bind(DGG.B1PRESS, self.startWindowDrag)

        # this is not handled correctly, if a window is dragged which has been
        # created before another it will not be released
        # check the bugfixed startWindowDrag function
        #self.windowHeader.bind(DGG.B1RELEASE,self.stopWindowDrag)

        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.attachNewNode(text)
        self.textNodePath.setScale(self.headerHeight * 0.8)

        # the content part of the window, put stuff beneath
        # contentWindow.getCanvas() to put it into it
        self.maxVirtualSize = maxSize
        self.minVirtualSize = minSize
        self.resizeSize = borderSize
        self.contentWindow = DirectScrolledFrame(
            parent=self,
            pos=(0, 0, -self.headerHeight),
            canvasSize=(0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1]),
            frameColor=(
                0, 0, 0,
                0),  # defines the background color of the resize-button
            relief=DGG.FLAT,
            borderWidth=(0, 0),
            verticalScroll_frameSize=[0, self.resizeSize, 0, 1],
            horizontalScroll_frameSize=[0, 1, 0, self.resizeSize],

            # resize the scrollbar according to window size
            verticalScroll_resizeThumb=False,
            horizontalScroll_resizeThumb=False,
            # define the textures for the scrollbars
            verticalScroll_frameTexture=VERTICALSCROLL_FRAMETEXTURE,
            verticalScroll_incButton_frameTexture=
            VERTICALSCROLL_INCBUTTON_FRAMETEXTURE,
            verticalScroll_decButton_frameTexture=
            VERTICALSCROLL_DECBUTTON_FRAMETEXTURE,
            verticalScroll_thumb_frameTexture=VERTICALSCROLL_TUMB_FRAMETEXTURE,
            horizontalScroll_frameTexture=HORIZONTALSCROLL_FRAMETEXTURE,
            horizontalScroll_incButton_frameTexture=
            HORIZONTALSCROLL_INCBUTTON_FRAMETEXTURE,
            horizontalScroll_decButton_frameTexture=
            HORIZONTALSCROLL_DECBUTTON_FRAMETEXTURE,
            horizontalScroll_thumb_frameTexture=
            HORIZONTALSCROLL_TUMB_FRAMETEXTURE,
            # make all flat, so the texture is as we want it
            verticalScroll_relief=DGG.FLAT,
            verticalScroll_thumb_relief=DGG.FLAT,
            verticalScroll_decButton_relief=DGG.FLAT,
            verticalScroll_incButton_relief=DGG.FLAT,
            horizontalScroll_relief=DGG.FLAT,
            horizontalScroll_thumb_relief=DGG.FLAT,
            horizontalScroll_decButton_relief=DGG.FLAT,
            horizontalScroll_incButton_relief=DGG.FLAT,
            # colors
            verticalScroll_frameColor=borderColor,
            verticalScroll_incButton_frameColor=borderColor,
            verticalScroll_decButton_frameColor=borderColor,
            verticalScroll_thumb_frameColor=borderColor,
            horizontalScroll_frameColor=borderColor,
            horizontalScroll_incButton_frameColor=borderColor,
            horizontalScroll_decButton_frameColor=borderColor,
            horizontalScroll_thumb_frameColor=borderColor,
        )
        self.contentWindow.setTransparency(True)

        # background color
        self.backgroundColor = DirectFrame(
            parent=self.contentWindow.getCanvas(),
            frameSize=(0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1]),
            frameColor=backgroundColor,
            relief=DGG.FLAT,
            borderWidth=(.01, .01),
        )
        self.backgroundColor.setTransparency(True)

        # Add a box
        self.box = boxes.VBox(parent=self.getCanvas())

        # is needed for some nicer visuals of the resize button (background)
        self.windowResizeBackground = DirectButton(
            parent=self,
            frameSize=(-.5, .5, -.5, .5),
            borderWidth=(0, 0),
            scale=(self.resizeSize, 1, self.resizeSize),
            relief=DGG.FLAT,
            frameColor=backgroundColor,
        )

        # the resize button of the window
        self.windowResize = DirectButton(
            parent=self,
            frameSize=(-.5, .5, -.5, .5),
            borderWidth=(0, 0),
            scale=(self.resizeSize, 1, self.resizeSize),
            relief=DGG.FLAT,
            frameTexture=DEFAULT_RESIZE_GEOM,
            frameColor=borderColor,
        )
        self.windowResize.setTransparency(True)
        self.windowResize.bind(DGG.B1PRESS, self.startResizeDrag)
        self.windowResize.bind(DGG.B1RELEASE, self.stopResizeDrag)

        # offset then clicking on the resize button from the mouse to the resizebutton
        # position, required to calculate the position / scaling
        self.offset = None
        self.taskName = "resizeTask-%s" % str(hash(self))

        # do sizing of the window (minimum)
        #self.resize( Vec3(0,0,0), Vec3(0,0,0) )
        # maximum
        #self.resize( Vec3(100,0,-100), Vec3(0,0,0) )
        self.resize(Vec3(curSize[0], 0, -curSize[1]), Vec3(0, 0, 0))

    def getCanvas(self):
        return self.contentWindow.getCanvas()

    # dragging functions
    def startWindowDrag(self, param):
        self.wrtReparentTo(aspect2dMouseNode)
        self.ignoreAll()
        self.accept('mouse1-up', self.stopWindowDrag)

    def stopWindowDrag(self, param=None):
        # this is called 2 times (bug), so make sure it's not already parented to aspect2d
        if self.getParent() != self.windowParent:
            self.wrtReparentTo(self.windowParent)
        if self.preserve:
            if self.preserveWhole:
                if self.getZ() > 1:
                    self.setZ(1)
                elif self.getZ() < -1 - self.getHeight():
                    self.setZ(-1 - self.getHeight())
                if self.getX() > base.a2dRight - self.getWidth():
                    self.setX(base.a2dRight - self.getWidth())
                elif self.getX() < base.a2dLeft:
                    self.setX(base.a2dLeft)
            else:
                if self.getZ() > 1:
                    self.setZ(1)
                elif self.getZ() < -1 + self.headerHeight:
                    self.setZ(-1 + self.headerHeight)
                if self.getX() > base.a2dRight - self.headerHeight:
                    self.setX(base.a2dRight - self.headerHeight)
                elif self.getX(
                ) < base.a2dLeft + self.headerHeight - self.getWidth():
                    self.setX(base.a2dLeft + self.headerHeight -
                              self.getWidth())
        #else: #Window moved beyond reach. Destroy window?

    # resize functions
    def resize(self, mPos, offset):
        mXPos = max(min(mPos.getX(), self.maxVirtualSize[0]),
                    self.minVirtualSize[0])
        mZPos = max(min(mPos.getZ(), -self.minVirtualSize[1]),
                    -self.maxVirtualSize[1] - self.headerHeight)
        self.windowResize.setPos(mXPos - self.resizeSize / 2., 0,
                                 mZPos + self.resizeSize / 2.)
        self.windowResizeBackground.setPos(mXPos - self.resizeSize / 2., 0,
                                           mZPos + self.resizeSize / 2.)
        self['frameSize'] = (0, mXPos, 0, mZPos)
        self.windowHeaderLeft.setPos(self.headerHeight / 2., 0,
                                     -self.headerHeight / 2.)
        self.windowHeaderLeft.setScale(self.headerHeight, 1, self.headerHeight)
        self.windowHeaderCenter.setPos(mXPos / 2., 0, -self.headerHeight / 2.)
        self.windowHeaderCenter.setScale(mXPos - self.headerHeight * 2., 1,
                                         self.headerHeight)
        self.windowHeaderRight.setPos(mXPos - self.headerHeight / 2., 0,
                                      -self.headerHeight / 2.)
        self.windowHeaderRight.setScale(self.headerHeight, 1,
                                        self.headerHeight)
        self.contentWindow['frameSize'] = (0, mXPos, mZPos + self.headerHeight,
                                           0)
        self.textNodePath.setPos(mXPos / 2., 0, -self.headerHeight / 3. * 2.)
        # show and hide that small background for the window sizer
        if mXPos == self.maxVirtualSize[0] and \
           mZPos == -self.maxVirtualSize[1]-self.headerHeight:
            self.windowResizeBackground.hide()
        else:
            self.windowResizeBackground.show()

    def resizeTask(self, task=None):
        mPos = aspect2dMouseNode.getPos(self) + self.offset
        self.resize(mPos, self.offset)
        return task.cont

    def startResizeDrag(self, param):
        self.offset = self.windowResize.getPos(aspect2dMouseNode)
        taskMgr.remove(self.taskName)
        taskMgr.add(self.resizeTask, self.taskName)

    def stopResizeDrag(self, param):
        taskMgr.remove(self.taskName)
        # get the window to the front
        self.wrtReparentTo(self.windowParent)

    def addHorizontal(self, widgets):
        """
      Accepts a list of directgui objects which are added to a horizontal box, which is then added to the vertical stack.
      """
        hbox = boxes.HBox()
        for widget in widgets:
            hbox.pack(widget)
        self.box.pack(hbox)
        self.updateMaxSize()

    def addVertical(self, widgets):
        """
      Accepts a list of directgui objects which are added to a vertical box, which is then added to the vertical stack.
      May cause funky layout results.
      """
        #vbox = boxes.VBox()
        for widget in widgets:
            self.box.pack(widget)
        self.updateMaxSize()

    def add(self, widgets):
        """Shortcut function for addVertical"""
        self.addVertical(widgets)

    def updateMaxSize(self):
        """Updates the max canvas size to include all items packed.
      Window is resized to show all contents."""
        bottomLeft, topRight = self.box.getTightBounds()
        self.maxVirtualSize = (topRight[0], -bottomLeft[2])
        self.contentWindow['canvasSize'] = (0, self.maxVirtualSize[0],
                                            -self.maxVirtualSize[1], 0)
        self.backgroundColor['frameSize'] = (0, self.maxVirtualSize[0],
                                             -self.maxVirtualSize[1], 0)

        #perhaps this should be optional -- automatically resize for new elements
        self.reset()

    def reset(self):
        """Poorly named function that resizes window to fit all contents"""
        self.resize(
            Vec3(self.maxVirtualSize[0], 0,
                 -self.maxVirtualSize[1] - self.headerHeight), Vec3(0, 0, 0))
Example #7
0
class CraftInventory(DirectObject):
    def __init__(self):
        self.itemFrame = DirectScrolledFrame(
            text="Inventory",
            text_scale=0.25,
            text_pos=(0, 0.75, 0),
            text_bg=(1, 1, 1, 1),
            # make the frame occupy the whole window
            frameSize=(-0.6, 0.6, -0.8, 0.8),
            pos=(-0.7, 0, 0),
            # make the canvas as big as the frame
            canvasSize=(-0.6, 0.6, -0.8, 0.8),
            # set the frames color to white
            frameColor=(1, 1, 1, 1))
        self.itemList = []

        self.craftFrame = DirectFrame(
            text="Crafting",
            text_scale=0.25,
            text_pos=(0, 0.75, 0),
            text_bg=(1, 1, 1, 1),
            # make the frame occupy the whole window
            frameSize=(-0.6, 0.6, -0.8, 0.8),
            pos=(0.7, 0, 0),
            # set the frames color to white
            frameColor=(1, 1, 1, 1))
        self.craftDrop = DirectFrame(text="drop ore",
                                     text_scale=0.1,
                                     pos=(0, 0.4, 0),
                                     frameSize=(-0.25, 0.25, -0.25, 0.25),
                                     frameColor=(1, 0, 0, 1))
        self.craftDrop.reparentTo(self.craftFrame)

    def show(self):
        self.itemFrame.show()
        self.craftFrame.show()

    def hide(self):
        self.itemFrame.hide()
        self.craftFrame.hide()

    def __makeItem(self, item):
        obj = DirectLabel(
            text=str(item.giveLoot()) + "x " + item.giveType(),
            text_scale=0.5,
            text_pos=(0, -1, 0),
            image=("item.png", "item_hover.png",
                   "item.png"),  #normal, hover, disabled
            scale=0.16,
            numStates=2,
            state=DGG.NORMAL,
            relief=DGG.GROOVE)
        obj.setTransparency(True)
        obj["activeState"] = 0
        obj.reparentTo(self.itemFrame.getCanvas())
        obj.bind(DGG.B1PRESS, self.dragStart, [obj])
        obj.bind(DGG.B1RELEASE, self.dragStop)
        obj.bind(DGG.ENTER, self.inObject, [obj])
        obj.bind(DGG.EXIT, self.outObject, [obj])
        return obj

    def updateList(self, items):
        for item in self.itemList:
            item.destroy()
        i = 1
        j = 0
        pad = 0.2
        numItemsPerRow = 2
        itemWidth = 0.32
        itemHeight = 0.32
        #left = -(itemWidth * (numItemsPerRow/2.0)) - 0.16
        left = self.itemFrame.getX()  # + (itemWidth + 0.16)
        xStep = itemWidth + 0.13
        yStep = -(itemHeight + 0.13)
        top = 0.8 - (0.16 + pad)
        for item in items:
            self.itemList.append(self.__makeItem(item))
            x = left + i * xStep
            y = top + j * yStep
            self.itemList[-1].setPos(x, 0.0, y)
            if i == numItemsPerRow:
                i = 0
                j += 1
            i += 1
        if i == 1: j -= 1
        height = ((j) * -yStep) - 0.16
        # resize the canvas. This will make the scrollbars dis-/appear,
        # dependent on if the canvas is bigger than the frame size.
        self.itemFrame["canvasSize"] = (-0.6, 0.6, -height, 0.8)

    def inObject(self, element, event):
        # Can be used to highlight objects
        element["activeState"] = 1
        element.setActiveState()
        #print "over object"

    def outObject(self, element, event):
        # Can be used to unhighlight objects
        #element["state"] = 0
        element["activeState"] = 0
        element.setActiveState()

    def dragStart(self, element, event):
        print "start drag"
        taskMgr.remove('dragDropTask')
        vWidget2render2d = element.getPos(render2d)
        vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1])
        editVec = Vec3(vWidget2render2d - vMouse2render2d)
        t = taskMgr.add(self.dragTask, 'dragDropTask')
        element.reparentTo(aspect2d)
        t.element = element
        t.editVec = editVec
        t.elementStartPos = element.getPos()

    def dragTask(self, state):
        mwn = base.mouseWatcherNode
        if mwn.hasMouse():
            vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
            newPos = vMouse2render2d + state.editVec
            state.element.setPos(render2d, newPos)
        return Task.cont

    def dragStop(self, event):
        print "stop drag with:", event
        isInArea = False

        t = taskMgr.getTasksNamed('dragDropTask')[0]
        #for dropArea in self.dropAreas:
        #    if self.isInBounds(event.getMouse(), dropArea["frameSize"], dropArea.getPos(render)):
        #        print "inside Area:", dropArea["text"], dropArea.getPos(render)
        #        isInArea = True
        #        t.element.setPos(dropArea.getPos(render))
        #        t.element.setX(t.element.getX() * self.ratio)
        #        #t.element.setX(t.element.getX() - t.element.getWidth() / 2.0)
        #        break

        if not isInArea:
            t.element.setPos(t.elementStartPos)
            t.element.reparentTo(self.itemFrame.getCanvas())
        taskMgr.remove('dragDropTask')

    def isInBounds(self, location, bounds, posShift=None):
        x = 0 if posShift is None else posShift.getX()
        y = 0 if posShift is None else posShift.getZ()

        left = x + bounds[0]
        right = x + bounds[1]
        bottom = y + bounds[2]
        top = y + bounds[3]

        # are we outside of the bounding box from the left
        if location[0] < left: return False
        # are we outside of the bounding box from the right
        if location[0] > right: return False
        # are we outside of the bounding box from the bottom
        if location[1] < bottom: return False
        # are we outside of the bounding box from the top
        if location[1] > top: return False
        # the location is inside the bbox
        return True
Example #8
0
class ViewEditor():
    __services: Services
    __base: ShowBase
    __window: Window
    __colour_picker: AdvancedColourPicker
    __elems: List[ViewElement]

    def __init__(self, services: Services,
                 mouse1_press_callbacks: List[Callable[[], None]]):
        self.__services = services
        self.__services.ev_manager.register_listener(self)
        self.__base = self.__services.graphics.window

        self.__window = Window(self.__base,
                               "view_editor",
                               mouse1_press_callbacks,
                               borderWidth=(0.0, 0.0),
                               frameColor=WINDOW_BG_COLOUR,
                               pos=(1.1, 0.5, 0.5),
                               frameSize=(-1.1, 1.1, -5.79, 1.56))

        self.__colour_picker = AdvancedColourPicker(
            self.__base, self.__window.frame, self.__colour_picker_callback,
            mouse1_press_callbacks)

        # spacers
        DirectFrame(parent=self.__window.frame,
                    borderWidth=(.0, .0),
                    frameColor=WIDGET_BG_COLOUR,
                    frameSize=(-1., 1., -0.01, 0.01),
                    pos=(0.0, 0.0, -1.75))

        DirectFrame(parent=self.__window.frame,
                    borderWidth=(.0, .0),
                    frameColor=WIDGET_BG_COLOUR,
                    frameSize=(-1., 1., -0.01, 0.01),
                    pos=(0.0, 0.0, 1.1))

        DirectFrame(parent=self.__window.frame,
                    borderWidth=(.0, .0),
                    frameColor=WIDGET_BG_COLOUR,
                    frameSize=(-1., 1., -0.01, 0.01),
                    pos=(0.0, 0.0, -4.1))

        # ViewElements listing
        self.__elems_frame = DirectScrolledFrame(parent=self.__window.frame,
                                                 frameColor=WINDOW_BG_COLOUR,
                                                 frameSize=(-1, 1, -1.125,
                                                            1.1),
                                                 pos=(0, 0, -2.9),
                                                 autoHideScrollBars=True)

        # selected colour view frame
        self.__selected_cv_outline = DirectFrame(
            parent=self.__elems_frame.getCanvas(),
            relief=DGG.SUNKEN,
            frameColor=WHITE,
            borderWidth=(0.15, 0.15),
            frameSize=(-0.62, 0.62, -0.54, 0.54),
            scale=(0.18, 1.0, 0.18))
        # selected view frame
        self.__selected_view_outline = DirectFrame(parent=self.__window.frame,
                                                   relief=DGG.SUNKEN,
                                                   frameColor=WHITE,
                                                   borderWidth=(0.15, 0.15),
                                                   frameSize=(-0.62, 0.62,
                                                              -0.54, 0.54),
                                                   scale=(0.3, 2.0, 0.35))

        self.heading = DirectLabel(parent=self.__window.frame,
                                   text="View Editor",
                                   text_fg=WHITE,
                                   text_bg=WINDOW_BG_COLOUR,
                                   frameColor=WINDOW_BG_COLOUR,
                                   borderWidth=(.0, .0),
                                   pos=(-0.42, 0.0, 1.27),
                                   scale=(0.2, 3, 0.2))

        self.__save_outline = DirectFrame(parent=self.__window.frame,
                                          frameColor=WHITE,
                                          pos=(-0.57, 0, -5.45),
                                          borderWidth=(0.25, 0.15),
                                          frameSize=(-0.62, 0.62, -0.54, 0.54),
                                          scale=(0.50, 2.1, 0.25))

        self.__restore_outline = DirectFrame(parent=self.__window.frame,
                                             frameColor=WHITE,
                                             pos=(0.50, 0, -5.45),
                                             borderWidth=(0.25, 0.15),
                                             frameSize=(-0.62, 0.62, -0.54,
                                                        0.54),
                                             scale=(0.65, 2.1, 0.25))

        # save and restore
        self.btn_s = DirectButton(text="Save",
                                  text_fg=(0.3, 0.3, 0.3, 1.0),
                                  pressEffect=1,
                                  command=self.__save,
                                  pos=(-0.575, 0, -5.5),
                                  parent=self.__window.frame,
                                  scale=(0.20, 2.1, 0.15),
                                  frameColor=TRANSPARENT)

        self.btn_r = DirectButton(text="Restore",
                                  text_fg=(0.3, 0.3, 0.3, 1.0),
                                  pressEffect=1,
                                  command=self.__reset,
                                  pos=(0.50, 0, -5.5),
                                  parent=self.__window.frame,
                                  scale=(0.20, 2.1, 0.15),
                                  frameColor=TRANSPARENT)

        # zoom window in / out
        self.btn_zoom_out = DirectButton(text="-",
                                         text_fg=WHITE,
                                         pressEffect=1,
                                         command=self.__window.zoom_out,
                                         pos=(0.5, 0., 1.25),
                                         parent=self.__window.frame,
                                         scale=(0.38, 4.25, 0.45),
                                         frameColor=TRANSPARENT)

        self.btn_zoom_in = DirectButton(text="+",
                                        text_fg=WHITE,
                                        pressEffect=1,
                                        command=self.__window.zoom_in,
                                        pos=(0.71, 0., 1.28),
                                        parent=self.__window.frame,
                                        scale=(0.35, 4.19, 0.38),
                                        frameColor=TRANSPARENT)

        # Quit button
        self.btn = DirectButton(text='x',
                                text_fg=WHITE,
                                command=self.__window.toggle_visible,
                                pos=(0.91, 0.4, 1.3),
                                parent=self.__window.frame,
                                scale=(0.3, 2.9, 0.2),
                                pressEffect=1,
                                frameColor=TRANSPARENT)

        # Creating view selectors
        self.__view_selectors = []
        for i in range(0, PersistentStateViews.MAX_VIEWS):
            num = os.path.join(GUI_DATA_PATH, str(i + 1) + ".png")

            self.__view_selectors.append(
                DirectButton(image=num,
                             pos=(-0.7 + (i % 3) * 0.7, 0.4,
                                  -4.4 - 0.5 * (i // 3)),
                             parent=self.__window.frame,
                             scale=0.16,
                             frameColor=TRANSPARENT,
                             command=lambda v: setattr(self, "view_idx", v),
                             extraArgs=[i]))

        self.__elems = []
        self.__reset()

    def __reset(self) -> None:
        self.__services.state.views.restore_effective_view()
        ps_colours = self.__services.state.views.effective_view.colours

        for e in self.__elems:
            e.destroy()
        self.__elems.clear()

        for name, dc in ps_colours.items():
            self.__elems.append(
                ViewElement(name, self.__update_visibility,
                            self.__update_colour, self.__select_cv,
                            self.__elems_frame.getCanvas(), dc.visible,
                            dc.colour))

        for i in range(len(self.__elems)):
            self.__elems[i].frame.set_pos((0.15, 0.0, -0.2 * i))
        self.__elems_frame["canvasSize"] = (-0.95, 0.95,
                                            -0.2 * len(self.__elems) + 0.1,
                                            0.1)

        self.__cur_view_idx = self.view_idx
        self.__selected_view_outline.set_pos(
            (-0.7 + (self.view_idx % 3) * 0.7, 0.4,
             -4.4 - 0.5 * (self.view_idx // 3)))

        self.__select_cv(self.__elems[0] if self.__elems else None)

    def __save(self) -> None:
        self.__services.state.views.apply_effective_view()

    def __update_visibility(self, name: str, visible: bool) -> None:
        self.__services.state.views.effective_view.colours[
            name].visible = visible

    def __update_colour(self, name: str, colour: Colour) -> None:
        self.__services.state.views.effective_view.colours[
            name].colour = colour

    def __colour_picker_callback(self, colour: Colour) -> None:
        self.__window.focus()
        if self.__selected_cv_elem is not None:
            self.__selected_cv_elem.colour = colour  # calls self.__update_colour()

    def __select_cv(self, e: ViewElement):
        self.__window.focus()
        self.__selected_cv_elem = e
        if e is None:
            self.__selected_cv_outline.hide()
            self.__colour_picker.enabled = False
        else:
            self.__colour_picker.enabled = True
            self.__selected_cv_outline.show()
            self.__selected_cv_outline.set_pos(
                (-0.495, 1.0, -0.2 * self.__elems.index(e)))
            self.__colour_picker.colour = e.colour

    def notify(self, event: Event) -> None:
        if isinstance(
                event, NewColourEvent
        ) or self.__services.state.views.view_idx != self.__cur_view_idx:
            self.__reset()
        elif isinstance(event, ToggleViewEvent):
            self.__window.toggle_visible()

    @property
    def view_idx(self) -> str:
        return 'view_idx'

    @view_idx.setter
    def view_idx(self, idx: int) -> None:
        self.__services.state.views.view_idx = idx
        self.__reset()

    @view_idx.getter
    def view_idx(self) -> int:
        return self.__services.state.views.view_idx
Example #9
0
class MappingGUIDemo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.setBackgroundColor(0, 0, 0)
        # make the font look nice at a big scale
        DGG.getDefaultFont().setPixelsPerUnit(100)

        # Store our mapping, with some sensible defaults.  In a real game, you
        # will want to load these from a configuration file.
        self.mapping = InputMapping()
        self.mapping.mapAxis("Move forward", InputDevice.Axis.left_y)
        self.mapping.mapAxis("Move backward", InputDevice.Axis.left_y)
        self.mapping.mapAxis("Move left", InputDevice.Axis.left_x)
        self.mapping.mapAxis("Move right", InputDevice.Axis.left_x)
        self.mapping.mapButton("Jump", GamepadButton.face_a())
        self.mapping.mapButton("Use", GamepadButton.face_b())
        self.mapping.mapButton("Break", GamepadButton.face_x())
        self.mapping.mapButton("Fix", GamepadButton.face_y())

        # The geometry for our basic buttons
        maps = loader.loadModel("models/button_map")
        self.buttonGeom = (maps.find("**/ready"), maps.find("**/click"),
                           maps.find("**/hover"), maps.find("**/disabled"))

        # Change the default dialog skin.
        DGG.setDefaultDialogGeom("models/dialog.png")

        # create a sample title
        self.textscale = 0.1
        self.title = DirectLabel(scale=self.textscale,
                                 pos=(base.a2dLeft + 0.05, 0.0,
                                      base.a2dTop - (self.textscale + 0.05)),
                                 frameColor=VBase4(0, 0, 0, 0),
                                 text="Button Mapping",
                                 text_align=TextNode.ALeft,
                                 text_fg=VBase4(1, 1, 1, 1),
                                 text_shadow=VBase4(0, 0, 0, 0.75),
                                 text_shadowOffset=Vec2(0.05, 0.05))
        self.title.setTransparency(1)

        # Set up the list of actions that we can map keys to
        # create a frame that will create the scrollbars for us
        # Load the models for the scrollbar elements
        thumbMaps = loader.loadModel("models/thumb_map")
        thumbGeom = (thumbMaps.find("**/thumb_ready"),
                     thumbMaps.find("**/thumb_click"),
                     thumbMaps.find("**/thumb_hover"),
                     thumbMaps.find("**/thumb_disabled"))
        incMaps = loader.loadModel("models/inc_map")
        incGeom = (incMaps.find("**/inc_ready"), incMaps.find("**/inc_click"),
                   incMaps.find("**/inc_hover"),
                   incMaps.find("**/inc_disabled"))
        decMaps = loader.loadModel("models/dec_map")
        decGeom = (decMaps.find("**/dec_ready"), decMaps.find("**/dec_click"),
                   decMaps.find("**/dec_hover"),
                   decMaps.find("**/dec_disabled"))

        # create the scrolled frame that will hold our list
        self.lstActionMap = DirectScrolledFrame(
            # make the frame occupy the whole window
            frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55),
            # make the canvas as big as the frame
            canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0),
            # set the frames color to white
            frameColor=VBase4(0, 0, 0.25, 0.75),
            pos=(0, 0, -0.8),
            verticalScroll_scrollSize=0.2,
            verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1),
            verticalScroll_thumb_relief=1,
            verticalScroll_thumb_geom=thumbGeom,
            verticalScroll_thumb_pressEffect=False,
            verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0),
            verticalScroll_incButton_relief=1,
            verticalScroll_incButton_geom=incGeom,
            verticalScroll_incButton_pressEffect=False,
            verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0),
            verticalScroll_decButton_relief=1,
            verticalScroll_decButton_geom=decGeom,
            verticalScroll_decButton_pressEffect=False,
            verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0),
        )

        # creat the list items
        idx = 0
        self.listBGEven = base.loader.loadModel("models/list_item_even")
        self.listBGOdd = base.loader.loadModel("models/list_item_odd")
        self.actionLabels = {}
        for action in self.mapping.actions:
            mapped = self.mapping.formatMapping(action)
            item = self.__makeListItem(action, mapped, idx)
            item.reparentTo(self.lstActionMap.getCanvas())
            idx += 1

        # recalculate the canvas size to set scrollbars if necesary
        self.lstActionMap["canvasSize"] = (base.a2dLeft + 0.05,
                                           base.a2dRight - 0.05,
                                           -(len(self.mapping.actions) * 0.1),
                                           0.09)
        self.lstActionMap.setCanvasSize()

    def closeDialog(self, action, newInputType, newInput):
        """Called in callback when the dialog is closed.  newInputType will be
        "button" or "axis", or None if the remapping was cancelled."""

        self.dlgInput = None

        if newInputType is not None:
            # map the event to the given action
            if newInputType == "axis":
                self.mapping.mapAxis(action, newInput)
            else:
                self.mapping.mapButton(action, newInput)

            # actualize the label in the list that shows the current
            # event for the action
            self.actionLabels[action]["text"] = self.mapping.formatMapping(
                action)

        # cleanup
        for bt in base.buttonThrowers:
            bt.node().setSpecificFlag(True)
            bt.node().setButtonDownEvent("")
        for bt in base.deviceButtonThrowers:
            bt.node().setSpecificFlag(True)
            bt.node().setButtonDownEvent("")
        taskMgr.remove("checkControls")

        # Now detach all the input devices.
        for device in self.attachedDevices:
            base.detachInputDevice(device)
        self.attachedDevices.clear()

    def changeMapping(self, action):
        # Create the dialog window
        self.dlgInput = ChangeActionDialog(action,
                                           button_geom=self.buttonGeom,
                                           command=self.closeDialog)

        # Attach all input devices.
        devices = base.devices.getDevices()
        for device in devices:
            base.attachInputDevice(device)
        self.attachedDevices = devices

        # Disable regular button events on all button event throwers, and
        # instead broadcast a generic event.
        for bt in base.buttonThrowers:
            bt.node().setSpecificFlag(False)
            bt.node().setButtonDownEvent("keyListenEvent")
        for bt in base.deviceButtonThrowers:
            bt.node().setSpecificFlag(False)
            bt.node().setButtonDownEvent("deviceListenEvent")

        self.accept("keyListenEvent", self.dlgInput.buttonPressed)
        self.accept("deviceListenEvent", self.dlgInput.buttonPressed)

        # As there are no events thrown for control changes, we set up a task
        # to check if the controls were moved
        # This list will help us for checking which controls were moved
        self.axisStates = {None: {}}
        # fill it with all available controls
        for device in devices:
            for axis in device.axes:
                if device not in self.axisStates.keys():
                    self.axisStates.update({device: {axis.axis: axis.value}})
                else:
                    self.axisStates[device].update({axis.axis: axis.value})
        # start the task
        taskMgr.add(self.watchControls, "checkControls")

    def watchControls(self, task):
        # move through all devices and all it's controls
        for device in self.attachedDevices:
            if device.device_class == InputDevice.DeviceClass.mouse:
                # Ignore mouse axis movement, or the user can't even navigate
                # to the OK/Cancel buttons!
                continue

            for axis in device.axes:
                # if a control got changed more than the given dead zone
                if self.axisStates[device][axis.axis] + DEAD_ZONE < axis.value or \
                   self.axisStates[device][axis.axis] - DEAD_ZONE > axis.value:
                    # set the current state in the dict
                    self.axisStates[device][axis.axis] = axis.value

                    # Format the axis for being displayed.
                    if axis.axis != InputDevice.Axis.none:
                        #label = axis.axis.name.replace('_', ' ').title()
                        self.dlgInput.axisMoved(axis.axis)

        return task.cont

    def __makeListItem(self, action, event, index):
        def dummy():
            pass

        if index % 2 == 0:
            bg = self.listBGEven
        else:
            bg = self.listBGOdd
        item = DirectFrame(text=action,
                           geom=bg,
                           geom_scale=(base.a2dRight - 0.05, 1, 0.1),
                           frameSize=VBase4(base.a2dLeft + 0.05,
                                            base.a2dRight - 0.05, -0.05, 0.05),
                           frameColor=VBase4(1, 0, 0, 0),
                           text_align=TextNode.ALeft,
                           text_scale=0.05,
                           text_fg=VBase4(1, 1, 1, 1),
                           text_pos=(base.a2dLeft + 0.3, -0.015),
                           text_shadow=VBase4(0, 0, 0, 0.35),
                           text_shadowOffset=Vec2(-0.05, -0.05),
                           pos=(0.05, 0, -(0.10 * index)))
        item.setTransparency(True)
        lbl = DirectLabel(
            text=event,
            text_fg=VBase4(1, 1, 1, 1),
            text_scale=0.05,
            text_pos=Vec2(0, -0.015),
            frameColor=VBase4(0, 0, 0, 0),
        )
        lbl.reparentTo(item)
        lbl.setTransparency(True)
        self.actionLabels[action] = lbl

        buttonScale = 0.15
        btn = DirectButton(text="Change",
                           geom=self.buttonGeom,
                           scale=buttonScale,
                           text_scale=0.25,
                           text_align=TextNode.ALeft,
                           text_fg=VBase4(0.898, 0.839, 0.730, 1.0),
                           text_pos=Vec2(-0.9, -0.085),
                           relief=1,
                           pad=Vec2(0.01, 0.01),
                           frameColor=VBase4(0, 0, 0, 0),
                           frameSize=VBase4(-1.0, 1.0, -0.25, 0.25),
                           pos=(base.a2dRight - (0.898 * buttonScale + 0.3), 0,
                                0),
                           pressEffect=False,
                           command=self.changeMapping,
                           extraArgs=[action])
        btn.setTransparency(True)
        btn.reparentTo(item)
        return item
Example #10
0
class MappingGUIDemo(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.setBackgroundColor(0, 0, 0)
        # make the font look nice at a big scale
        DGG.getDefaultFont().setPixelsPerUnit(100)

        # Store our mapping, with some sensible defaults.  In a real game, you
        # will want to load these from a configuration file.
        self.mapping = InputMapping()
        self.mapping.mapAxis("Move forward", InputDevice.Axis.left_y)
        self.mapping.mapAxis("Move backward", InputDevice.Axis.left_y)
        self.mapping.mapAxis("Move left", InputDevice.Axis.left_x)
        self.mapping.mapAxis("Move right", InputDevice.Axis.left_x)
        self.mapping.mapButton("Jump", GamepadButton.face_a())
        self.mapping.mapButton("Use", GamepadButton.face_b())
        self.mapping.mapButton("Break", GamepadButton.face_x())
        self.mapping.mapButton("Fix", GamepadButton.face_y())

        # The geometry for our basic buttons
        maps = loader.loadModel("models/button_map")
        self.buttonGeom = (
            maps.find("**/ready"),
            maps.find("**/click"),
            maps.find("**/hover"),
            maps.find("**/disabled"))

        # Change the default dialog skin.
        DGG.setDefaultDialogGeom("models/dialog.png")

        # create a sample title
        self.textscale = 0.1
        self.title = DirectLabel(
            scale=self.textscale,
            pos=(base.a2dLeft + 0.05, 0.0, base.a2dTop - (self.textscale + 0.05)),
            frameColor=VBase4(0, 0, 0, 0),
            text="Button Mapping",
            text_align=TextNode.ALeft,
            text_fg=VBase4(1, 1, 1, 1),
            text_shadow=VBase4(0, 0, 0, 0.75),
            text_shadowOffset=Vec2(0.05, 0.05))
        self.title.setTransparency(1)

        # Set up the list of actions that we can map keys to
        # create a frame that will create the scrollbars for us
        # Load the models for the scrollbar elements
        thumbMaps = loader.loadModel("models/thumb_map")
        thumbGeom = (
            thumbMaps.find("**/thumb_ready"),
            thumbMaps.find("**/thumb_click"),
            thumbMaps.find("**/thumb_hover"),
            thumbMaps.find("**/thumb_disabled"))
        incMaps = loader.loadModel("models/inc_map")
        incGeom = (
            incMaps.find("**/inc_ready"),
            incMaps.find("**/inc_click"),
            incMaps.find("**/inc_hover"),
            incMaps.find("**/inc_disabled"))
        decMaps = loader.loadModel("models/dec_map")
        decGeom = (
            decMaps.find("**/dec_ready"),
            decMaps.find("**/dec_click"),
            decMaps.find("**/dec_hover"),
            decMaps.find("**/dec_disabled"))

        # create the scrolled frame that will hold our list
        self.lstActionMap = DirectScrolledFrame(
            # make the frame occupy the whole window
            frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55),
            # make the canvas as big as the frame
            canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0),
            # set the frames color to white
            frameColor=VBase4(0, 0, 0.25, 0.75),
            pos=(0, 0, -0.8),

            verticalScroll_scrollSize=0.2,
            verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1),

            verticalScroll_thumb_relief=1,
            verticalScroll_thumb_geom=thumbGeom,
            verticalScroll_thumb_pressEffect=False,
            verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0),

            verticalScroll_incButton_relief=1,
            verticalScroll_incButton_geom=incGeom,
            verticalScroll_incButton_pressEffect=False,
            verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0),

            verticalScroll_decButton_relief=1,
            verticalScroll_decButton_geom=decGeom,
            verticalScroll_decButton_pressEffect=False,
            verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0),)

        # creat the list items
        idx = 0
        self.listBGEven = base.loader.loadModel("models/list_item_even")
        self.listBGOdd = base.loader.loadModel("models/list_item_odd")
        self.actionLabels = {}
        for action in self.mapping.actions:
            mapped = self.mapping.formatMapping(action)
            item = self.__makeListItem(action, mapped, idx)
            item.reparentTo(self.lstActionMap.getCanvas())
            idx += 1

        # recalculate the canvas size to set scrollbars if necesary
        self.lstActionMap["canvasSize"] = (
            base.a2dLeft+0.05, base.a2dRight-0.05,
            -(len(self.mapping.actions)*0.1), 0.09)
        self.lstActionMap.setCanvasSize()

    def closeDialog(self, action, newInputType, newInput):
        """Called in callback when the dialog is closed.  newInputType will be
        "button" or "axis", or None if the remapping was cancelled."""

        self.dlgInput = None

        if newInputType is not None:
            # map the event to the given action
            if newInputType == "axis":
                self.mapping.mapAxis(action, newInput)
            else:
                self.mapping.mapButton(action, newInput)

            # actualize the label in the list that shows the current
            # event for the action
            self.actionLabels[action]["text"] = self.mapping.formatMapping(action)

        # cleanup
        for bt in base.buttonThrowers:
            bt.node().setSpecificFlag(True)
            bt.node().setButtonDownEvent("")
        for bt in base.deviceButtonThrowers:
            bt.node().setSpecificFlag(True)
            bt.node().setButtonDownEvent("")
        taskMgr.remove("checkControls")

        # Now detach all the input devices.
        for device in self.attachedDevices:
            base.detachInputDevice(device)
        self.attachedDevices.clear()

    def changeMapping(self, action):
        # Create the dialog window
        self.dlgInput = ChangeActionDialog(action, button_geom=self.buttonGeom, command=self.closeDialog)

        # Attach all input devices.
        devices = base.devices.getDevices()
        for device in devices:
            base.attachInputDevice(device)
        self.attachedDevices = devices

        # Disable regular button events on all button event throwers, and
        # instead broadcast a generic event.
        for bt in base.buttonThrowers:
            bt.node().setSpecificFlag(False)
            bt.node().setButtonDownEvent("keyListenEvent")
        for bt in base.deviceButtonThrowers:
            bt.node().setSpecificFlag(False)
            bt.node().setButtonDownEvent("deviceListenEvent")

        self.accept("keyListenEvent", self.dlgInput.buttonPressed)
        self.accept("deviceListenEvent", self.dlgInput.buttonPressed)

        # As there are no events thrown for control changes, we set up a task
        # to check if the controls were moved
        # This list will help us for checking which controls were moved
        self.axisStates = {None: {}}
        # fill it with all available controls
        for device in devices:
            for axis in device.axes:
                if device not in self.axisStates.keys():
                    self.axisStates.update({device: {axis.axis: axis.value}})
                else:
                    self.axisStates[device].update({axis.axis: axis.value})
        # start the task
        taskMgr.add(self.watchControls, "checkControls")

    def watchControls(self, task):
        # move through all devices and all it's controls
        for device in self.attachedDevices:
            if device.device_class == InputDevice.DeviceClass.mouse:
                # Ignore mouse axis movement, or the user can't even navigate
                # to the OK/Cancel buttons!
                continue

            for axis in device.axes:
                # if a control got changed more than the given dead zone
                if self.axisStates[device][axis.axis] + DEAD_ZONE < axis.value or \
                   self.axisStates[device][axis.axis] - DEAD_ZONE > axis.value:
                    # set the current state in the dict
                    self.axisStates[device][axis.axis] = axis.value

                    # Format the axis for being displayed.
                    if axis.axis != InputDevice.Axis.none:
                        #label = axis.axis.name.replace('_', ' ').title()
                        self.dlgInput.axisMoved(axis.axis)

        return task.cont

    def __makeListItem(self, action, event, index):
        def dummy(): pass
        if index % 2 == 0:
            bg = self.listBGEven
        else:
            bg = self.listBGOdd
        item = DirectFrame(
            text=action,
            geom=bg,
            geom_scale=(base.a2dRight-0.05, 1, 0.1),
            frameSize=VBase4(base.a2dLeft+0.05, base.a2dRight-0.05, -0.05, 0.05),
            frameColor=VBase4(1,0,0,0),
            text_align=TextNode.ALeft,
            text_scale=0.05,
            text_fg=VBase4(1,1,1,1),
            text_pos=(base.a2dLeft + 0.3, -0.015),
            text_shadow=VBase4(0, 0, 0, 0.35),
            text_shadowOffset=Vec2(-0.05, -0.05),
            pos=(0.05, 0, -(0.10 * index)))
        item.setTransparency(True)
        lbl = DirectLabel(
            text=event,
            text_fg=VBase4(1, 1, 1, 1),
            text_scale=0.05,
            text_pos=Vec2(0, -0.015),
            frameColor=VBase4(0, 0, 0, 0),
            )
        lbl.reparentTo(item)
        lbl.setTransparency(True)
        self.actionLabels[action] = lbl

        buttonScale = 0.15
        btn = DirectButton(
            text="Change",
            geom=self.buttonGeom,
            scale=buttonScale,
            text_scale=0.25,
            text_align=TextNode.ALeft,
            text_fg=VBase4(0.898, 0.839, 0.730, 1.0),
            text_pos=Vec2(-0.9, -0.085),
            relief=1,
            pad=Vec2(0.01, 0.01),
            frameColor=VBase4(0, 0, 0, 0),
            frameSize=VBase4(-1.0, 1.0, -0.25, 0.25),
            pos=(base.a2dRight-(0.898*buttonScale+0.3), 0, 0),
            pressEffect=False,
            command=self.changeMapping,
            extraArgs=[action])
        btn.setTransparency(True)
        btn.reparentTo(item)
        return item
Example #11
0
class TextScrolledFrame(object):
    def __init__(self,
                 parent=None,
                 scale=.05,
                 limitText=1,
                 frameSize=(0, 1.3, .2, .697),
                 pos=(0, 0, .1)):

        self.__scale = scale
        self.__frameSize = frameSize
        self.__canvasSize = (frameSize[0], frameSize[2] - .01, frameSize[2],
                             frameSize[3])
        self.__limitText = limitText
        self.__countLine = []

        self.dsf = DirectScrolledFrame(
            parent=parent,
            canvasSize=self.__canvasSize,
            frameSize=self.__frameSize,
            pos=pos,
            frameColor=COR_OPACITY_03_PRETO,
            autoHideScrollBars=1,
            scrollBarWidth=0.05,
            borderWidth=(0, 0),
            verticalScroll_value=1,
            verticalScroll_decButton_frameColor=(1, 1, 1, 0.3),
            verticalScroll_decButton_rolloverSound=None,
            verticalScroll_decButton_clickSound=None,
            verticalScroll_incButton_frameColor=(1, 1, 1, 0.3),
            verticalScroll_incButton_rolloverSound=None,
            verticalScroll_incButton_clickSound=None,
            verticalScroll_thumb_frameColor=(1, 1, 1, 0.3),
            verticalScroll_thumb_rolloverSound=None,
            verticalScroll_thumb_clickSound=None)

        self.__textoHeight = scale
        self.__canvasHeight = self.dsf.getHeight()
        self.__canvas = self.dsf.getCanvas()

    def __command_clear_msg(self):
        self.etyMsg.set("")

    def __reposicionaTexto(self, obj_text):
        height = obj_text.getScale() * obj_text.textNode.getNumRows()

        for text in self.__countLine:
            lastPos = text.textNodePath.getPos()
            text.setPos((lastPos[0], 0, lastPos[2] + height))

    def __resizeCanvasSize(self, text):

        self.__textoHeight += text.getScale() * text.textNode.getNumRows()

        if self.__textoHeight > self.__canvasHeight:
            self.__canvasHeight += self.__textoHeight - self.__canvasHeight

        self.dsf['canvasSize'] = (self.dsf['canvasSize'][0],
                                  self.dsf['canvasSize'][1],
                                  self.dsf['canvasSize'][2],
                                  self.dsf['canvasSize'][2] +
                                  self.__canvasHeight)
        self.dsf.setCanvasSize()

    def show(self, texto, cor=(1, 1, 1, 1)):

        dfs_pos = self.dsf.getPos()

        pos = (dfs_pos[0] + .01, 0, dfs_pos[1] + 0.16)

        text = Text(parent=self.__canvas,
                    scale=self.__scale,
                    text=texto,
                    wordwrap=25,
                    pos=pos,
                    cor=cor)

        numText = len(self.__countLine)
        if numText > 0:
            self.__reposicionaTexto(text)

        self.__countLine.append(text)

        if numText > self.__limitText:
            self.__countLine[0].remove()
            self.__countLine.pop(0)
        else:
            self.__resizeCanvasSize(text)

        self.dsf['verticalScroll_value'] = 1
Example #12
0
class ScrolledButtonsList(DirectObject):
    """
       A class to display a list of selectable buttons.
       It is displayed using scrollable window (DirectScrolledFrame).
    """
    def __init__(self, parent=None, frameSize=(.8,1.2), buttonTextColor=(1,1,1,1),
                 font=None, itemScale=.045, itemTextScale=0.85, itemTextZ=0,
                 command=None, contextMenu=None, autoFocus=0,
                 colorChange=1, colorChangeDuration=1, newItemColor=globals.colors['guiblue1'],
                 rolloverColor=globals.colors['guiyellow'],
                 suppressMouseWheel=1, modifier='control'):
        self.mode = None
        self.focusButton=None
        self.command=command
        self.contextMenu=contextMenu
        self.autoFocus=autoFocus
        self.colorChange=colorChange
        self.colorChangeDuration=colorChangeDuration*.5
        self.newItemColor=newItemColor
        self.rolloverColor=rolloverColor
        self.rightClickTextColors=(Vec4(0,1,0,1),Vec4(0,35,100,1))
        self.font=font
        if font:
           self.fontHeight=font.getLineHeight()
        else:
           self.fontHeight=TextNode.getDefaultFont().getLineHeight()
        self.fontHeight*=1.2 # let's enlarge font height a little
        self.xtraSideSpace=.2*self.fontHeight
        self.itemTextScale=itemTextScale
        self.itemTextZ=itemTextZ
        self.buttonTextColor=buttonTextColor
        self.suppressMouseWheel=suppressMouseWheel
        self.modifier=modifier
        self.buttonsList=[]
        self.numItems=0
        self.__eventReceivers={}
        # DirectScrolledFrame to hold items
        self.itemScale=itemScale
        self.itemVertSpacing=self.fontHeight*self.itemScale
        self.frameWidth,self.frameHeight=frameSize
        # I set canvas' Z size smaller than the frame to avoid the auto-generated vertical slider bar
        self.childrenFrame = DirectScrolledFrame(
                     parent=parent,pos=(-self.frameWidth*.5,0,.5*self.frameHeight), relief=DGG.GROOVE,
                     state=DGG.NORMAL, # to create a mouse watcher region
                     frameSize=(0, self.frameWidth, -self.frameHeight, 0), frameColor=(0,0,0,.7),
                     canvasSize=(0, 0, -self.frameHeight*.5, 0), borderWidth=(0.01,0.01),
                     manageScrollBars=0, enableEdit=0, suppressMouse=0, sortOrder=1000 )
        # the real canvas is "self.childrenFrame.getCanvas()",
        # but if the frame is hidden since the beginning,
        # no matter how I set the canvas Z pos, the transform would be resistant,
        # so just create a new node under the canvas to be my canvas
        self.canvas=self.childrenFrame.getCanvas().attachNewNode('myCanvas')
        # slider background
        SliderBG=DirectFrame( parent=self.childrenFrame,frameSize=(-.025,.025,-self.frameHeight,0),
                     frameColor=(0,0,0,.7), pos=(-.03,0,0),enableEdit=0, suppressMouse=0)
        # slider thumb track
        sliderTrack = DirectFrame( parent=SliderBG, relief=DGG.FLAT, #state=DGG.NORMAL,
                     frameColor=(1,1,1,.2), frameSize=(-.015,.015,-self.frameHeight+.01,-.01),
                     enableEdit=0, suppressMouse=0)
        # page up
        self.pageUpRegion=DirectFrame( parent=SliderBG, relief=DGG.FLAT, state=DGG.NORMAL,
                     frameColor=(1,.8,.2,.1), frameSize=(-.015,.015,0,0),
                     enableEdit=0, suppressMouse=0)
        self.pageUpRegion.setAlphaScale(0)
        self.pageUpRegion.bind(DGG.B1PRESS,self.__startScrollPage,[-1])
        self.pageUpRegion.bind(DGG.WITHIN,self.__continueScrollUp)
        self.pageUpRegion.bind(DGG.WITHOUT,self.__suspendScrollUp)
        # page down
        self.pageDnRegion=DirectFrame( parent=SliderBG, relief=DGG.FLAT, state=DGG.NORMAL,
                     frameColor=(1,.8,.2,.1), frameSize=(-.015,.015,0,0),
                     enableEdit=0, suppressMouse=0)
        self.pageDnRegion.setAlphaScale(0)
        self.pageDnRegion.bind(DGG.B1PRESS,self.__startScrollPage,[1])
        self.pageDnRegion.bind(DGG.WITHIN,self.__continueScrollDn)
        self.pageDnRegion.bind(DGG.WITHOUT,self.__suspendScrollDn)
        self.pageUpDnSuspended=[0,0]
        # slider thumb
        self.vertSliderThumb=DirectButton(parent=SliderBG, relief=DGG.FLAT,
                     frameColor=(1,1,1,.6), frameSize=(-.015,.015,0,0),
                     enableEdit=0, suppressMouse=0, rolloverSound=None, clickSound=None)
        self.vertSliderThumb.bind(DGG.B1PRESS,self.__startdragSliderThumb)
        self.vertSliderThumb.bind(DGG.WITHIN,self.__enteringThumb)
        self.vertSliderThumb.bind(DGG.WITHOUT,self.__exitingThumb)
        self.oldPrefix=base.buttonThrowers[0].node().getPrefix()
        self.sliderThumbDragPrefix='draggingSliderThumb-'
        # GOD & I DAMN IT !!!
        # These things below don't work well if the canvas has a lot of buttons.
        # So I end up checking the mouse region every frame by myself using a continuous task.
  #       self.accept(DGG.WITHIN+self.childrenFrame.guiId,self.__enteringFrame)
  #       self.accept(DGG.WITHOUT+self.childrenFrame.guiId,self.__exitingFrame)
        self.isMouseInRegion=False
        self.mouseOutInRegionCommand=(self.__exitingFrame,self.__enteringFrame)
        taskMgr.doMethodLater(.2,self.__getFrameRegion,'getFrameRegion')
  
    def __getFrameRegion(self,t):
        for g in range(base.mouseWatcherNode.getNumGroups()):
            region=base.mouseWatcherNode.getGroup(g).findRegion(self.childrenFrame.guiId)
            if region!=None:
               self.frameRegion=region
               taskMgr.add(self.__mouseInRegionCheck,'mouseInRegionCheck')
               break
  
    def __mouseInRegionCheck(self,t):
        """
           check if the mouse is within or without the scrollable frame, and
           upon within or without, run the provided command
        """
        if not base.mouseWatcherNode.hasMouse(): return Task.cont
        m=base.mouseWatcherNode.getMouse()
        bounds=self.frameRegion.getFrame()
        inRegion=bounds[0]<m[0]<bounds[1] and bounds[2]<m[1]<bounds[3]
        if self.isMouseInRegion==inRegion: return Task.cont
        self.isMouseInRegion=inRegion
        self.mouseOutInRegionCommand[inRegion]()
        return Task.cont
  
    def __startdragSliderThumb(self,m=None):
        if self.mode != None:
            if hasattr(self.mode, 'enableMouseCamControl') == 1:
                if self.mode.enableMouseCamControl == 1:
                    self.mode.game.app.disableMouseCamControl()
        mpos=base.mouseWatcherNode.getMouse()
        parentZ=self.vertSliderThumb.getParent().getZ(render2d)
        sliderDragTask=taskMgr.add(self.__dragSliderThumb,'dragSliderThumb')
        sliderDragTask.ZposNoffset=mpos[1]-self.vertSliderThumb.getZ(render2d)+parentZ
  #       sliderDragTask.mouseX=base.winList[0].getPointer(0).getX()
        self.oldPrefix=base.buttonThrowers[0].node().getPrefix()
        base.buttonThrowers[0].node().setPrefix(self.sliderThumbDragPrefix)
        self.acceptOnce(self.sliderThumbDragPrefix+'mouse1-up',self.__stopdragSliderThumb)
  
    def __dragSliderThumb(self,t):
        if not base.mouseWatcherNode.hasMouse():
           return
        mpos=base.mouseWatcherNode.getMouse()
  #       newY=base.winList[0].getPointer(0).getY()
        self.__updateCanvasZpos((t.ZposNoffset-mpos[1])/self.canvasRatio)
  #       base.winList[0].movePointer(0, t.mouseX, newY)
        return Task.cont
  
    def __stopdragSliderThumb(self,m=None):
        if self.mode != None:
            if hasattr(self.mode, 'enableMouseCamControl') == 1:
                if self.mode.enableMouseCamControl == 1:
                    self.mode.game.app.enableMouseCamControl()
        taskMgr.remove('dragSliderThumb')
        self.__stopScrollPage()
        base.buttonThrowers[0].node().setPrefix(self.oldPrefix)
        if self.isMouseInRegion:
           self.mouseOutInRegionCommand[self.isMouseInRegion]()
  
    def __startScrollPage(self,dir,m):
        self.oldPrefix=base.buttonThrowers[0].node().getPrefix()
        base.buttonThrowers[0].node().setPrefix(self.sliderThumbDragPrefix)
        self.acceptOnce(self.sliderThumbDragPrefix+'mouse1-up',self.__stopdragSliderThumb)
        t=taskMgr.add(self.__scrollPage,'scrollPage',extraArgs=[int((dir+1)*.5),dir*.01/self.canvasRatio])
        self.pageUpDnSuspended=[0,0]
  
    def __scrollPage(self,dir,scroll):
        if not self.pageUpDnSuspended[dir]:
           self.__scrollCanvas(scroll)
        return Task.cont
  
    def __stopScrollPage(self,m=None):
        taskMgr.remove('scrollPage')
  
    def __suspendScrollUp(self,m=None):
        self.pageUpRegion.setAlphaScale(0)
        self.pageUpDnSuspended[0]=1
    def __continueScrollUp(self,m=None):
        if taskMgr.hasTaskNamed('dragSliderThumb'):
           return
        self.pageUpRegion.setAlphaScale(1)
        self.pageUpDnSuspended[0]=0
   
    def __suspendScrollDn(self,m=None):
        self.pageDnRegion.setAlphaScale(0)
        self.pageUpDnSuspended[1]=1
    def __continueScrollDn(self,m=None):
        if taskMgr.hasTaskNamed('dragSliderThumb'):
           return
        self.pageDnRegion.setAlphaScale(1)
        self.pageUpDnSuspended[1]=0
  
    def __suspendScrollPage(self,m=None):
        self.__suspendScrollUp()
        self.__suspendScrollDn()
   
    def __enteringThumb(self,m=None):
        self.vertSliderThumb['frameColor']=(1,1,1,1)
        self.__suspendScrollPage()
  
    def __exitingThumb(self,m=None):
        self.vertSliderThumb['frameColor']=(1,1,1,.6)
  
    def __scrollCanvas(self,scroll):
        if self.vertSliderThumb.isHidden() or self.buttonsList == []:
           return
        self.__updateCanvasZpos(self.canvas.getZ()+scroll)
  
    def __updateCanvasZpos(self,Zpos):
        newZ=clampScalar(Zpos, .0, self.canvasLen-self.frameHeight+.015)
        self.canvas.setZ(newZ)
        thumbZ=-newZ*self.canvasRatio
        self.vertSliderThumb.setZ(thumbZ)
        self.pageUpRegion['frameSize']=(-.015,.015,thumbZ-.01,-.01)
        self.pageDnRegion['frameSize']=(-.015,.015,-self.frameHeight+.01,thumbZ+self.vertSliderThumb['frameSize'][2])
  
    def __adjustCanvasLength(self,numItem):
        self.canvasLen=float(numItem)*self.itemVertSpacing
        self.canvasRatio=(self.frameHeight-.015)/(self.canvasLen+.01)
        if self.canvasLen<=self.frameHeight-.015:
           canvasZ=.0
           self.vertSliderThumb.hide()
           self.pageUpRegion.hide()
           self.pageDnRegion.hide()
           self.canvasLen=self.frameHeight-.015
        else:
           canvasZ=self.canvas.getZ()
           self.vertSliderThumb.show()
           self.pageUpRegion.show()
           self.pageDnRegion.show()
        self.__updateCanvasZpos(canvasZ)
        self.vertSliderThumb['frameSize']=(-.015,.015,-self.frameHeight*self.canvasRatio,-.01)
        thumbZ=self.vertSliderThumb.getZ()
        self.pageUpRegion['frameSize']=(-.015,.015,thumbZ-.01,-.01)
        self.pageDnRegion['frameSize']=(-.015,.015,-self.frameHeight+.01,thumbZ+self.vertSliderThumb['frameSize'][2])
  
    def __acceptAndIgnoreWorldEvent(self,event,command,extraArgs=[]):
        receivers=messenger.whoAccepts(event)
        if receivers is None:
           self.__eventReceivers[event]={}
        else:
           self.__eventReceivers[event]=receivers.copy()
        for r in self.__eventReceivers[event].keys():
            if type(r) != types.TupleType:
                r.ignore(event)
        self.accept(event,command,extraArgs)
  
    def __ignoreAndReAcceptWorldEvent(self,events):
        for event in events:
            self.ignore(event)
            if self.__eventReceivers.has_key(event):
               for r, method_xtraArgs_persist in self.__eventReceivers[event].items():
                   if type(r) != types.TupleType:
                       messenger.accept(event,r,*method_xtraArgs_persist)
            self.__eventReceivers[event]={}
  
    def __enteringFrame(self,m=None):
        # sometimes the WITHOUT event for page down region doesn't fired,
        # so directly suspend the page scrolling here
        self.__suspendScrollPage()
        BTprefix=base.buttonThrowers[0].node().getPrefix()
        if BTprefix==self.sliderThumbDragPrefix:
           return
        self.inOutBTprefix=BTprefix
        if self.suppressMouseWheel:
           self.__acceptAndIgnoreWorldEvent(self.inOutBTprefix+'wheel_up',
                command=self.__scrollCanvas, extraArgs=[-.07])
           self.__acceptAndIgnoreWorldEvent(self.inOutBTprefix+'wheel_down',
                command=self.__scrollCanvas, extraArgs=[.07])
        else:
           self.accept(self.inOutBTprefix+self.modifier+'-wheel_up',self.__scrollCanvas, [-.07])
           self.accept(self.inOutBTprefix+self.modifier+'-wheel_down',self.__scrollCanvas, [.07])
  
    def __exitingFrame(self,m=None):
        if not hasattr(self,'inOutBTprefix'):
           return
        if self.suppressMouseWheel:
           self.__ignoreAndReAcceptWorldEvent( (
                                               self.inOutBTprefix+'wheel_up',
                                               self.inOutBTprefix+'wheel_down',
                                               ) )
        else:
           self.ignore(self.inOutBTprefix+self.modifier+'-wheel_up')
           self.ignore(self.inOutBTprefix+self.modifier+'-wheel_down')
  
    def __setFocusButton(self,button,item):
        if self.focusButton:
           self.restoreNodeButton2Normal()
        self.focusButton=button
        self.highlightNodeButton()
        if callable(self.command) and button in self.buttonsList:
           # run user command and pass the selected item, it's index, and the button
           self.command(item,self.buttonsList.index(button),button)
  
    def __rightPressed(self,button,m):
        self.__isRightIn=True
  #       text0 : normal
  #       text1 : pressed
  #       text2 : rollover
  #       text3 : disabled
        button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rightClickTextColors[self.focusButton==button])
        button.bind(DGG.B3RELEASE,self.__rightReleased,[button])
        button.bind(DGG.WITHIN,self.__rightIn,[button])
        button.bind(DGG.WITHOUT,self.__rightOut,[button])
  
    def __rightIn(self,button,m):
        self.__isRightIn=True
        button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rightClickTextColors[self.focusButton==button])
    def __rightOut(self,button,m):
        self.__isRightIn=False
        button._DirectGuiBase__componentInfo['text2'][0].setColorScale(Vec4(1,1,1,1))
  
    def __rightReleased(self,button,m):
        button.unbind(DGG.B3RELEASE)
        button.unbind(DGG.WITHIN)
        button.unbind(DGG.WITHOUT)
        button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rolloverColor)
        if not self.__isRightIn:
           return
        if callable(self.contextMenu):
           # run user command and pass the selected item, it's index, and the button
           self.contextMenu(button['extraArgs'][1],self.buttonsList.index(button),button)

    def scrollToBottom(self):
        ##for i in range(0,self.numItems):
        self.__scrollCanvas(1)

    def selectButton(self, button, item):
        self.__setFocusButton(button, item)
  
    def restoreNodeButton2Normal(self):
        """
           stop highlighting item
        """
        if self.focusButton != None:
            #self.focusButton['text_fg']=(1,1,1,1)
            self.focusButton['frameColor']=(0,0,0,0)
  
    def highlightNodeButton(self,idx=None):
        """
           highlight the item
        """
        if idx is not None:
            self.focusButton=self.buttonsList[idx]
        #self.focusButton['text_fg']=(.01,.01,.01,1)
        # nice dark blue.  don't mess with the text fg color though! we want it custom
        self.focusButton['frameColor']=(0,.3,.8,1)
  
    def clear(self):
        """
           clear the list
        """
        for c in self.buttonsList:
            c.remove()
        self.buttonsList=[]
        self.focusButton=None
        self.numItems=0
  
    def addItem(self,text,extraArgs=None,atIndex=None,textColorName=None):
        """
           add item to the list
           text : text for the button
           extraArgs : the object which will be passed to user command(s)
                       (both command and contextMenu) when the button get clicked
           atIndex : where to add the item
                     <None> : put item at the end of list
                     <integer> : put item at index <integer>
                     <button> : put item at <button>'s index
            textColorName : the color name eg. 'yellow'
        """
        textColor = self.buttonTextColor
        if textColorName != None:
            textColor = globals.colors[textColorName]
            
        button = DirectButton(parent=self.canvas,
            scale=self.itemScale,
            relief=DGG.FLAT,
            frameColor=(0,0,0,0),text_scale=self.itemTextScale,
            text=text, text_pos=(0,self.itemTextZ),text_fg=textColor,
            text_font=self.font, text_align=TextNode.ALeft,
            command=self.__setFocusButton,
            enableEdit=0, suppressMouse=0, rolloverSound=None,clickSound=None)
        #button.setMyMode(self.mode)
        l,r,b,t=button.getBounds()
        # top & bottom are blindly set without knowing where exactly the baseline is,
        # but this ratio fits most fonts
        baseline=-self.fontHeight*.25
        #button['saved_color'] = textColor
        button['frameSize']=(l-self.xtraSideSpace,r+self.xtraSideSpace,baseline,baseline+self.fontHeight)
  
  #          Zc=NodePath(button).getBounds().getCenter()[1]-self.fontHeight*.5+.25
  # #          Zc=button.getCenter()[1]-self.fontHeight*.5+.25
  #          button['frameSize']=(l-self.xtraSideSpace,r+self.xtraSideSpace,Zc,Zc+self.fontHeight)
       
        button['extraArgs']=[button,extraArgs]
        button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rolloverColor)
        button.bind(DGG.B3PRESS,self.__rightPressed,[button])
        if isinstance(atIndex,DirectButton):
           if atIndex.isEmpty():
              atIndex=None
           else:
              index=self.buttonsList.index(atIndex)
              self.buttonsList.insert(index,button)
        if atIndex==None:
           self.buttonsList.append(button)
           index=self.numItems
        elif type(atIndex)==IntType:
           index=atIndex
           self.buttonsList.insert(index,button)
        Zpos=(-.7-index)*self.itemVertSpacing
        button.setPos(.02,0,Zpos)
        if index!=self.numItems:
           for i in range(index+1,self.numItems+1):
               self.buttonsList[i].setZ(self.buttonsList[i],-self.fontHeight)
        self.numItems+=1
        self.__adjustCanvasLength(self.numItems)
        if self.autoFocus:
           self.focusViewOnItem(index)
        if self.colorChange:
           Sequence(
              button.colorScaleInterval(self.colorChangeDuration,self.newItemColor,globals.colors['guiblue3']),
              button.colorScaleInterval(self.colorChangeDuration,Vec4(1,1,1,1),self.newItemColor)
              ).start()
  
    def focusViewOnItem(self,idx):
        """
           Scroll the window so the newly added item will be displayed
           in the middle of the window, if possible.
        """
        Zpos=(idx+.7)*self.itemVertSpacing-self.frameHeight*.5
        self.__updateCanvasZpos(Zpos)
       
    def setAutoFocus(self,b):
        """
           set auto-view-focus state of newly added item
        """
        self.autoFocus=b
  
    def index(self,button):
        """
           get the index of button
        """
        if not button in self.buttonsList:
           return None
        return self.buttonsList.index(button)
       
    def getNumItems(self):
        """
           get the current number of items on the list
        """
        return self.numItems
  
    def disableItem(self,i):
        if not 0<=i<self.numItems:
           print 'DISABLING : invalid index (%s)' %i
           return
        self.buttonsList[i]['state']=DGG.DISABLED
        self.buttonsList[i].setColorScale(.3,.3,.3,1)
   
    def enableItem(self,i):
        if not 0<=i<self.numItems:
           print 'ENABLING : invalid index (%s)' %i
           return
        self.buttonsList[i]['state']=DGG.NORMAL
        self.buttonsList[i].setColorScale(1,1,1,1)
  
    def removeItem(self,index):
        if not 0<=index<self.numItems:
           print 'REMOVAL : invalid index (%s)' %index
           return
        if self.numItems==0: return
        if self.focusButton==self.buttonsList[index]:
           self.focusButton=None
        self.buttonsList[index].removeNode()
        del self.buttonsList[index]
        self.numItems-=1
        for i in range(index,self.numItems):
            self.buttonsList[i].setZ(self.buttonsList[i],self.fontHeight)
        self.__adjustCanvasLength(self.numItems)
  
    def destroy(self):
        self.clear()
        self.__exitingFrame()
        self.ignoreAll()
        self.childrenFrame.removeNode()
        taskMgr.remove('mouseInRegionCheck')
  
    def hide(self):
        self.childrenFrame.hide()
        self.isMouseInRegion=False
        self.__exitingFrame()
        taskMgr.remove('mouseInRegionCheck')
  
    def show(self):
        self.childrenFrame.show()
        if not hasattr(self,'frameRegion'):
           taskMgr.doMethodLater(.2,self.__getFrameRegion,'getFrameRegion')
        elif not taskMgr.hasTaskNamed('mouseInRegionCheck'):
           taskMgr.add(self.__mouseInRegionCheck,'mouseInRegionCheck')
  
    def toggleVisibility(self):
        if self.childrenFrame.isHidden():
           self.show()
        else:
           self.hide()
  
    def setMyMode(self, myMode):
        self.mode = myMode
Example #13
0
class HostMenu(DirectObject):
    def __init__(self):
        self.defaultBtnMap = base.loader.loadModel("gui/button_map")
        self.buttonGeom = (self.defaultBtnMap.find("**/button_ready"),
                           self.defaultBtnMap.find("**/button_click"),
                           self.defaultBtnMap.find("**/button_rollover"),
                           self.defaultBtnMap.find("**/button_disabled"))

        defaultFont = loader.loadFont('gui/eufm10.ttf')

        self.logFrame = DirectScrolledFrame(
            canvasSize=(0, base.a2dRight * 2, -5, 0),
            frameSize=(0, base.a2dRight * 2, (base.a2dBottom + .2) * 2, 0),
            frameColor=(0.1, 0.1, 0.1, 1))
        self.logFrame.reparentTo(base.a2dTopLeft)

        # create the info and server debug output
        self.textscale = 0.1
        self.txtinfo = OnscreenText(scale=self.textscale,
                                    pos=(0.1, -0.1),
                                    text="",
                                    align=TextNode.ALeft,
                                    fg=(0.1, 1.0, 0.15, 1),
                                    bg=(0, 0, 0, 0),
                                    shadow=(0, 0, 0, 1),
                                    shadowOffset=(-0.02, -0.02))
        self.txtinfo.setTransparency(1)
        self.txtinfo.reparentTo(self.logFrame.getCanvas())

        # create a close Server button
        self.btnBackPos = Vec3(0.4, 0, 0.2)
        self.btnBackScale = 0.25
        self.btnBack = DirectButton(
            # Scale and position
            scale=self.btnBackScale,
            pos=self.btnBackPos,
            # Text
            text="Quit Server",
            text_scale=0.45,
            text_pos=(0, -0.1),
            text_fg=(0.82, 0.85, 0.87, 1),
            text_shadow=(0, 0, 0, 1),
            text_shadowOffset=(-0.02, -0.02),
            text_font=defaultFont,
            # Frame
            geom=self.buttonGeom,
            frameColor=(0, 0, 0, 0),
            relief=0,
            pressEffect=False,
            # Functionality
            command=self.back,
            rolloverSound=None,
            clickSound=None)
        self.btnBack.setTransparency(1)
        self.btnBack.reparentTo(base.a2dBottomLeft)

        # catch window resizes and recalculate the aspectration
        self.accept("window-event", self.recalcAspectRatio)
        self.accept("addLog", self.addLog)

    def show(self):
        self.logFrame.show()
        self.btnBack.show()

    def hide(self):
        self.logFrame.hide()
        self.btnBack.hide()

    def back(self):
        self.hide()
        base.messenger.send("stop_server")
        self.addLog("Quit Server!")

    def addLog(self, text):
        self.txtinfo.appendText(text + "\n")
        textbounds = self.txtinfo.getTightBounds()
        self.logFrame["canvasSize"] = (0, textbounds[1].getX(),
                                       textbounds[0].getZ(), 0)

    def recalcAspectRatio(self, window):
        """get the new aspect ratio to resize the mainframe"""
        # set the mainframe size to the window borders again
        self.logFrame["frameSize"] = (0, base.a2dRight * 2,
                                      (base.a2dBottom + .2) * 2, 0)
Example #14
0
class DirectTree(DirectObject):
    def __init__(
            self,
            pos=(0, 0, 0),
            parent=None,
            frameSize=(1, 1),
            treeStructure=DirectTreeItem(),
    ):
        if parent is None:
            parent = aspect2d
        self.treeStructure = treeStructure
        self.treeStructureNodes = dict()

        self.highlightedNodes = list()

        self.frameWidth = frameSize[0]  #0.8
        self.frameHeight = frameSize[1]  #1.5

        self.itemIndent = 0.05
        self.itemScale = 0.03
        self.itemTextScale = 1.2
        self.verticalSpacing = 0.0375
        self.__createTreeLines()

        self.childrenFrame = DirectScrolledFrame(
            parent=parent,
            pos=pos,
            relief=DGG.GROOVE,
            state=DGG.NORMAL,  # to create a mouse watcher region
            manageScrollBars=0,
            enableEdit=0,
            #suppressMouse=1,
            sortOrder=1000,
            frameColor=(0, 0, 0, .7),
            borderWidth=(0.005, 0.005),
            frameSize=(0, self.frameWidth, 0, self.frameHeight),
            canvasSize=(0, self.frameWidth - self.itemScale * 2, 0,
                        self.frameHeight),
            verticalScroll_frameSize=[0, self.itemScale, 0, 1],
            horizontalScroll_frameSize=[0, 1, 0, self.itemScale],
        )
        self.childrenCanvas = self.childrenFrame.getCanvas().attachNewNode(
            'myCanvas')
        self.childrenCanvas.setX(0.05)
        self.childrenCanvas.setZ(self.frameHeight -
                                 1)  # some fix to have the list in the window

        self.accept(EVENT_DIRECTTREE_REFRESH, self.update)

    def destroy(self):
        self.treeStructure = DirectTreeItem()
        self.render()
        self.childrenFrame.destroy()
        #del self.treeStructureNodes

    def __createLine(self, length=1, color=(1, 1, 1, 1), endColor=None):
        LS = LineSegs()
        LS.setColor(*color)
        LS.moveTo(0, 0, 0)
        LS.drawTo(length * 1, 0, 0)
        node = LS.create()
        if endColor:
            LS.setVertexColor(1, *endColor)
        return node

    def __createTreeLines(self):
        # create horisontal tree line
        color = (1, 0, 0, .9)
        self.horizontalTreeLine = NodePath(
            self.__createLine(self.itemIndent + self.itemScale * .5,
                              color,
                              endColor=(1, 1, 1, .1)))
        self.horizontalTreeLine.setTwoSided(0, 100)
        self.horizontalTreeLine.setTransparency(1)
        # create vertical tree line
        self.verticalTreeLine = NodePath(
            self.__createLine(self.verticalSpacing, color))
        self.verticalTreeLine.setR(90)
        self.verticalTreeLine.setTwoSided(0, 100)
        self.verticalTreeLine.setTransparency(1)

    def render(self):
        ''' traverse the tree and update the visuals according to it
    '''
        for treeItem in self.treeStructure.getRec():
            # create nodes that have no visual elements
            if not treeItem in self.treeStructureNodes:
                treeNode = self.childrenCanvas.attachNewNode('')

                hor = self.horizontalTreeLine.instanceUnderNode(treeNode, '')
                vert = self.verticalTreeLine.instanceUnderNode(treeNode, '')
                vert.setZ(0.007)
                hor.setPos(-1.5 * self.itemIndent, 0, self.itemScale * .25)
                vert.setX(-.5 * self.itemIndent)

                nodeButton = DirectButton(
                    parent=treeNode,
                    scale=self.itemScale,
                    relief=DGG.FLAT,
                    text_scale=self.itemTextScale,
                    text_align=TextNode.ALeft,
                    text=treeItem.name,
                    rolloverSound=None,
                    #clickSound=None,
                )
                nodeButton.bind(DGG.B1PRESS, treeItem.button1press)
                nodeButton.bind(DGG.B2PRESS, treeItem.button2press)
                nodeButton.bind(DGG.B3PRESS, treeItem.button3press)

                #treeButton = None
                #if len(treeItem.childrens) > 0:
                treeButton = DirectButton(
                    parent=nodeButton,
                    frameColor=(1, 1, 1, 1),
                    frameSize=(-.4, .4, -.4, .4),
                    pos=(-.5 * self.itemIndent / self.itemScale, 0, .25),
                    text='',
                    text_pos=(-.1, -.22),
                    text_scale=(1.6, 1),
                    text_fg=(0, 0, 0, 1),
                    enableEdit=0,
                    command=treeItem.setOpen,
                    sortOrder=1000,
                    rolloverSound=None,
                    #clickSound=None,
                )

                self.treeStructureNodes[treeItem] = [
                    treeNode, nodeButton, treeButton, hor, vert
                ]

        # destroy nodes no more used
        for treeItem in self.treeStructureNodes.keys()[:]:
            #treeItem = self.treeStructureNodes[treeName]
            if treeItem not in self.treeStructure.getRec():
                treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[
                    treeItem]
                #nodeButton['text']=''
                nodeButton.unbind(DGG.B1PRESS)
                nodeButton.unbind(DGG.B2PRESS)
                nodeButton.unbind(DGG.B3PRESS)
                #nodeButton.detachNode()
                #nodeButton.removeNode()
                nodeButton.destroy()
                if treeButton:
                    #treeButton['text']=''
                    #treeButton['command']=None
                    treeButton.detachNode()
                    treeButton.removeNode()
                hor.detachNode()
                hor.removeNode()
                vert.detachNode()
                vert.removeNode()
                treeItem.destroy()
                #treeNode.detachNode()
                treeNode.removeNode()
                #treeNode.destroy()
                del self.treeStructureNodes[treeItem]

        frameHeight = len(self.treeStructureNodes) * self.verticalSpacing
        self.childrenFrame['canvasSize'] = (0, self.frameWidth -
                                            self.itemScale * 2, 0, frameHeight)
        self.childrenCanvas.setZ(frameHeight - 1)

    def highlight(self, selectedTreeNodes):
        for treeNode in self.highlightedNodes:
            treeNode.highlighted = False
        self.highlightedNodes = selectedTreeNodes
        for treeNode in self.highlightedNodes:
            treeNode.highlighted = True
        self.update()

    def update(self):
        ''' update the tree, updating the positions and hidden status of childrens
    '''
        idx = 0
        for treeItem in self.treeStructure.getRec():
            # show or hide the items
            treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[
                treeItem]
            if treeItem.getShow():
                treeNode.show()
                vert.show()
                if treeItem.parent:  # dont show the horizontal line on the parent
                    hor.show()
                else:
                    hor.hide()
                idx += 1
            else:
                treeNode.hide()
                hor.hide()
                vert.hide()

            if len(treeItem.childrens) > 0:
                treeButton.show()
            else:
                treeButton.hide()

            if treeItem.highlighted:
                nodeButton['text_fg'] = (1, 0, 0, 1)
            else:
                nodeButton['text_fg'] = (0, 0, 0, 1)

            # update the vertical position of the node
            treeNode.setPos(treeItem.getDepth() * self.itemIndent, 0,
                            1 - idx * self.verticalSpacing)

            # if the tree element has a treebutton (if it has childrens), update the +/-
            if treeButton:
                # update the text for the open/close button
                tag = ['+', '-'][treeItem.open]
                treeButton['text'] = tag

            # calculate length to the last children with the same depth as this treeitem
            # this gives the length of the vertical line
            c = -1
            i = 0
            treeItemDepth = treeItem.getDepth()
            for recItem in treeItem.getRec():
                if recItem.getShow():
                    c += 1
                if recItem.getDepth() == treeItemDepth + 1:
                    i = c
            vert.setSz(i)
Example #15
0
class Journal:
    """Captain's journal GUI object.

    Args:
        winned (bool):
            Flag, saying if the player already won the game.
    """

    def __init__(self, winned=False):
        self._is_shown = False
        self._read_coordinates = False
        self._winned = winned
        self._opened_num = None

        self._main_fr = DirectFrame(
            parent=base.a2dTopLeft,  # noqa: F821
            frameSize=(-0.37, 0.38, -0.6, 0.6),
            state=DGG.NORMAL,
            pos=(0.37, 0, -1),
            frameTexture="gui/tex/paper1.png",
        )
        self._main_fr.setTransparency(TransparencyAttrib.MAlpha)
        self._main_fr.hide()

        self._fr = DirectScrolledFrame(
            parent=self._main_fr,
            frameSize=(-0.35, 0.3, -0.46, 0.5),
            frameColor=(0, 0, 0, 0),
            canvasSize=(-0.31, 0.3, -3, 1.5),
            state=DGG.NORMAL,
            pos=(0, 0, -0.1),
            verticalScroll_frameSize=(-0.003, 0.003, -0.5, 0.5),
            verticalScroll_frameColor=(0.46, 0.41, 0.37, 1),
            verticalScroll_thumb_frameColor=(0.31, 0.26, 0.22, 1),
            verticalScroll_incButton_relief=None,
            verticalScroll_decButton_relief=None,
            horizontalScroll_relief=None,
            horizontalScroll_thumb_relief=None,
            horizontalScroll_incButton_relief=None,
            horizontalScroll_decButton_relief=None,
        )
        DirectLabel(  # Journal
            parent=self._main_fr,
            text=base.labels.JOURNAL[0],  # noqa: F821
            text_font=base.cursive_font,  # noqa: F821
            text_scale=0.053,
            text_bg=(0, 0, 0, 0),
            text_fg=(0, 0, 0.25, 1),
            frameSize=(0.1, 0.1, 0.1, 0.1),
            pos=(-0.34, 0, 0.52),
            text_align=TextNode.ALeft,
        )
        DirectButton(
            parent=self._main_fr,
            text="<",
            text_scale=0.06,
            text_bg=(0, 0, 0, 0),
            text_fg=(0, 0, 0.25, 1),
            pos=(-0.15, 0, 0.45),
            frameSize=(-0.2, 0.2, -0.2, 0.2),
            relief=None,
            command=self._open_page,
            extraArgs=[-1],
        )
        DirectButton(
            parent=self._main_fr,
            text=">",
            text_scale=0.06,
            text_bg=(0, 0, 0, 0),
            text_fg=(0, 0, 0.25, 1),
            pos=(0.15, 0, 0.45),
            frameSize=(-0.2, 0.2, -0.2, 0.2),
            relief=None,
            command=self._open_page,
            extraArgs=[1],
        )
        self._page_title = DirectLabel(
            parent=self._main_fr,
            text="",
            text_scale=0.043,
            text_font=base.cursive_font,  # noqa: F821
            text_fg=(0, 0, 0.25, 1),
            frameSize=(-0.02, 0.02, -3.5, 0.5),
            frameColor=(0, 0, 0, 0),
            pos=(0, 0, 0.45),
        )
        self._page_text = DirectLabel(
            parent=self._fr.getCanvas(),
            text="",
            text_scale=0.045,
            text_font=base.cursive_font,  # noqa: F821
            text_align=TextNode.ALeft,
            text_fg=(0, 0, 0.25, 1),
            frameSize=(-0.02, 0.02, -3.5, 0.5),
            frameColor=(0, 0, 0, 0),
            pos=(-0.27, 0, 1.45),
        )
        self._pages = []

        self._open_snd = loader.loadSfx("sounds/GUI/journal.ogg")  # noqa: F821
        self._page_snd = loader.loadSfx("sounds/GUI/journal_page.ogg")  # noqa: F821
        self._close_snd = loader.loadSfx("sounds/GUI/journal_close.ogg")  # noqa: F821

    @property
    def winned(self):
        """The flag indicating if the player already won.

        Returns:
            bool: True if the player already won, False otherwise.
        """
        return self._winned

    def _open_page(self, shift):
        """Open the given page of the journal.

        Args:
            shift (int): Page number shift.
        """
        if self._opened_num is None:
            return

        if (
            self._opened_num + shift > len(self._pages) - 1
            or self._opened_num + shift < 0
        ):
            return

        self._opened_num += shift
        self._page_text["text"] = self._pages[self._opened_num]["page"]
        self._page_title["text"] = self._pages[self._opened_num]["title"]
        self._page_snd.play()

        if self._opened_num == 7:
            self._read_coordinates = True

    def add_page(self, num):
        """Add a page into the journal.

        Args:
            num (int): The page number.
        """
        type_, title, page_text = base.labels.JOURNAL_PAGES[num]  # noqa: F821
        page_rec = {"page": page_text, "type": type_, "title": title}

        self._pages.append(page_rec)

        if self._opened_num is None:
            self._opened_num = 0
            self._page_text["text"] = self._pages[self._opened_num]["page"]
            self._page_title["text"] = self._pages[self._opened_num]["title"]

    def show(self):
        """Show/hide the journal GUI."""
        if self._is_shown:
            self._main_fr.hide()
            self._close_snd.play()
            if not self._winned and self._read_coordinates:
                self._winned = True

                page = DirectFrame(
                    frameSize=(-0.73, 0.73, -0.9, 0.9),
                    frameTexture="gui/tex/paper1.png",
                    state=DGG.NORMAL,
                )
                page.setDepthTest(False)
                page.setTransparency(TransparencyAttrib.MAlpha)
                page.show()

                DirectLabel(
                    parent=page,
                    text=base.labels.UNTERRIFF_DISCOVERED_TITLE,  # noqa: F821
                    text_font=base.main_font,  # noqa: F821
                    frameSize=(0.6, 0.6, 0.6, 0.6),
                    text_scale=0.043,
                    pos=(0, 0, 0.65),
                )

                DirectLabel(
                    parent=page,
                    text=base.labels.UNTERRIFF_DISCOVERED,  # noqa: F821
                    text_font=base.main_font,  # noqa: F821
                    frameSize=(0.6, 0.6, 0.6, 0.6),
                    text_scale=0.037,
                    pos=(0, 0, 0.55),
                )

                DirectButton(  # Done
                    parent=page,
                    pos=(0, 0, -0.77),
                    text=base.labels.DISTINGUISHED[6],  # noqa: F821
                    text_font=base.main_font,  # noqa: F821
                    text_fg=RUST_COL,
                    text_shadow=(0, 0, 0, 1),
                    frameColor=(0, 0, 0, 0),
                    command=page.destroy,
                    extraArgs=[],
                    scale=(0.05, 0, 0.05),
                    clickSound=base.main_menu.click_snd,  # noqa: F821
                )

            self._read_coordinates = False
        else:
            self._main_fr.show()
            self._open_snd.play()

        self._is_shown = not self._is_shown
class ScrolledItemSelector(DirectObject):
    '''Touch optimised list that holds a set of items. By clicking on one you select it and return
    its Value with get_selected(). To add an item simply use add_item(). You can also pass a
    function with the 'command' field that gets called on a selection switch'''
    def __init__(self,
                 frame_size=(1, 1.5),
                 frame_color=(0.2, 0.2, 0.2, 0.8),
                 pos=(0, 0, 0),
                 item_v_padding=0.02,
                 item_h_padding=0.04,
                 item_scale=1,
                 item_side_ratio=0.2,
                 item_background=(0.3, 0.3, 0.3, 1),
                 item_background_active=(0.6, 0.6, 0.6, 1),
                 command=lambda: None):

        self.f_x, self.f_y = frame_size
        self.c_x = self.f_x
        self.c_y = self.f_y

        self.item_v_padding = item_v_padding
        self.item_h_padding = item_h_padding
        self.item_scale = item_scale
        self.item_background = item_background
        self.item_background_active = item_background_active

        self.frame = DirectScrolledFrame(
            frameSize=(-self.f_x / 2, self.f_x / 2, -self.f_y / 2,
                       self.f_y / 2),
            canvasSize=(-self.c_x / 2, self.c_x / 2, -self.c_y / 2,
                        self.c_y / 2),
            frameColor=frame_color,
            pos=pos,
            scrollBarWidth=(0),
            manageScrollBars=False,
            state=DGG.NORMAL)

        self.frame.verticalScroll.destroy()
        self.frame.horizontalScroll.destroy()
        self.frame.bind(DGG.WITHIN, self._start_listening)
        self.frame.bind(DGG.WITHOUT, self._stop_listening)

        self.canvas = self.frame.getCanvas()

        self.i_x = self.f_x * (1 - item_h_padding)
        self.i_y = self.f_y * item_side_ratio
        self.i_size = (-self.i_x / 2, self.i_x / 2, -self.i_y / 2,
                       self.i_y / 2)

        self.i_start = self.c_y / 2 + self.i_y / 2

        self.active_item = None
        self.item_list = []
        self.value_list = []

        self.start_mY = None
        self.old_mY = None
        self.m_diff = 0
        self.is_scrolling = False
        self.command = command

        # messenger.toggleVerbose()

    def _start_listening(self, watcher):
        print('start listening')
        self.accept("mouse1", self._start_scroll)
        self.accept("mouse1-up", self._stop_scroll)

    def _stop_listening(self, watcher):
        print('stop listening')
        self.ignore("mouse1")
        self.ignore("mouse1-up")
        self._stop_scroll()

    def _switch_active_item(self, item, watcher):
        if not self.is_scrolling:
            print('switched')
            if self.active_item is not None:
                self.active_item['frameColor'] = self.item_background
            item['frameColor'] = self.item_background_active
            self.active_item = item
            self.command()

    def _start_scroll(self):
        n = len(self.item_list)
        content_length = (
            (n * (self.i_y + self.item_v_padding))
            +  # Size of all elements with padding
            self.item_v_padding)  # Add one padding for the bottom

        if content_length > self.c_y:
            taskMgr.doMethodLater(0.01, self._scroll_task, 'scroll_task')
            self.start_mY = base.mouseWatcherNode.getMouse().getY()
            self.old_mY = self.start_mY

    def _stop_scroll(self):
        taskMgr.remove('scroll_task')
        taskMgr.doMethodLater(0.01, self._scroll_fade_task, 'scrollfadetask')
        self.is_scrolling = False

    def _scroll_task(self, task):
        mY = base.mouseWatcherNode.getMouse().getY()
        old_c = self.canvas.getZ()
        self.m_diff = self.old_mY - mY
        n = len(self.item_list)

        if self.m_diff != 0:
            self.is_scrolling = True

        self.c_scroll_start = 0
        self.c_scroll_stop = (
            (n * (self.i_y + self.item_v_padding))
            +  # Size of all elements with padding
            self.item_v_padding -  # Add one padding for the bottom
            self.f_y)  # Substract the length of the canvas
        self.c_new_pos = (old_c - self.m_diff)

        hits_not_upper_bound = self.c_new_pos >= self.c_scroll_start
        hits_not_lower_bound = self.c_new_pos <= self.c_scroll_stop

        # print('canvas : ' + str(self.canvas.getZ()))

        if hits_not_upper_bound and hits_not_lower_bound:
            self.canvas.setZ(self.c_new_pos)
        elif not hits_not_upper_bound:
            self.canvas.setZ(self.c_scroll_start)
        elif not hits_not_lower_bound:
            self.canvas.setZ(self.c_scroll_stop)

        self.old_mY = mY
        return task.again

    def _scroll_fade_task(self, task):
        if self.m_diff is None or abs(self.m_diff) < 0.005:
            self.m_diff = 0
            return task.done

        old_c = self.canvas.getZ()
        n = len(self.item_list)
        self.c_scroll_start = 0
        self.c_scroll_stop = (
            (n * (self.i_y + self.item_v_padding))
            +  # Size of all elements with padding
            self.item_v_padding -  # Add one padding for the bottom
            self.c_y)  # Substract the length of the canvas

        hits_not_upper_bound = (old_c - self.m_diff) >= self.c_scroll_start
        hits_not_lower_bound = (old_c - self.m_diff) <= self.c_scroll_stop

        if hits_not_upper_bound and hits_not_lower_bound:
            self.canvas.setZ(old_c - self.m_diff)
            self.m_diff *= 0.85
            return task.again
        elif not hits_not_upper_bound:
            self.canvas.setZ(self.c_scroll_start)
            self.m_diff = 0
            return task.done
        elif not hits_not_lower_bound:
            self.canvas.setZ(self.c_scroll_stop)
            self.m_diff = 0
            return task.done

    def add_item(self,
                 image=None,
                 image_scale=0.15,
                 image_pos=(0, 0, 0),
                 title=None,
                 title_pos=(0, 0, 0),
                 text=None,
                 text_pos=(0, 0, 0),
                 value=None):
        '''Appends an item to the end of the list. It can hold an image,
        title and text. Image: Panda3d path eg. 'models/picture.jpg'.
        Value: The item has function 'get/set_value()' to work with individual
        values of an activated element. Value gets set to the item on adding it.'''

        item_nr = len(self.item_list) + 1
        item_pos = self.i_start - (self.i_y + self.item_v_padding) * item_nr

        item = DirectFrame(
            parent=self.canvas,
            text=str(item_nr),  # Abused as an ID tag
            text_fg=(0, 0, 0, 0),
            frameSize=self.i_size,
            frameColor=self.item_background,
            borderWidth=(0.01, 0.01),
            pos=(0, 0, item_pos),
            relief=DGG.FLAT,
            state=DGG.NORMAL,
            enableEdit=0,
            suppressMouse=0)
        item.bind(DGG.B1RELEASE, self._switch_active_item, [item])

        if image is not None:
            OnscreenImage(  # Add an Image
                image=image,
                pos=image_pos,
                scale=(1 * image_scale, 1, 1 * image_scale),
                parent=(item))

        DirectLabel(
            parent=item,  # Add a Title
            text=title,
            text_scale=self.i_y / 4,
            text_fg=(1, 1, 1, 1),
            text_align=TextNode.ALeft,
            frameColor=(0, 0, 0, 0),
            pos=title_pos)

        DirectLabel(
            parent=item,  # Add a Text
            text=text,
            text_scale=self.i_y / 5,
            text_fg=(1, 1, 1, 1),
            text_align=TextNode.ALeft,
            frameColor=(0, 0, 0, 0),
            pos=text_pos)

        self.item_list.append(item)
        self.value_list.append(value)

    def get_active_item(self):
        return self.active_item

    def set_active_item(self, pos):
        self._switch_active_item(self.item_list[pos], None)

    def get_active_id(self):
        return int(self.active_item['text'])

    def get_active_value(self):
        return self.value_list[int(self.active_item['text']) - 1]

    def hide(self):
        '''Triggers the DirectFrame.hide() of the main frame'''

        self.frame.hide()

    def show(self):
        '''Triggers the DirectFrame.show() of the main frame'''

        self.frame.show()

    def clear(self):
        '''Destroys every item that was added to the list'''

        for item in self.item_list:
            item.destroy()
        self.item_list = []
        self.active_item = None
        self.value_list = []
        self.canvas.setZ(0)

    def destroy(self):
        '''Destroys the whole list and every item in it'''

        self.canvas.destroy()
        self.frame.destroy()
Example #17
0
class CraftInventory(DirectObject):
    def __init__(self):
        self.itemFrame = DirectScrolledFrame(
            text="Inventory",
            text_scale=0.25,
            text_pos=(0, 0.75, 0),
            text_bg=(1, 1, 1, 1),
            # make the frame occupy the whole window
            frameSize=(-0.6, 0.6, -0.8, 0.8),
            pos=(-0.7, 0, 0),
            # make the canvas as big as the frame
            canvasSize=(-0.6, 0.6, -0.8, 0.8),
            # set the frames color to white
            frameColor=(1, 1, 1, 1),
        )
        self.itemList = []

        self.craftFrame = DirectFrame(
            text="Crafting",
            text_scale=0.25,
            text_pos=(0, 0.75, 0),
            text_bg=(1, 1, 1, 1),
            # make the frame occupy the whole window
            frameSize=(-0.6, 0.6, -0.8, 0.8),
            pos=(0.7, 0, 0),
            # set the frames color to white
            frameColor=(1, 1, 1, 1),
        )
        self.craftDrop = DirectFrame(
            text="drop ore",
            text_scale=0.1,
            pos=(0, 0.4, 0),
            frameSize=(-0.25, 0.25, -0.25, 0.25),
            frameColor=(1, 0, 0, 1),
        )
        self.craftDrop.reparentTo(self.craftFrame)

    def show(self):
        self.itemFrame.show()
        self.craftFrame.show()

    def hide(self):
        self.itemFrame.hide()
        self.craftFrame.hide()

    def __makeItem(self, item):
        obj = DirectLabel(
            text=str(item.giveLoot()) + "x " + item.giveType(),
            text_scale=0.5,
            text_pos=(0, -1, 0),
            image=("item.png", "item_hover.png", "item.png"),  # normal, hover, disabled
            scale=0.16,
            numStates=2,
            state=DGG.NORMAL,
            relief=DGG.GROOVE,
        )
        obj.setTransparency(True)
        obj["activeState"] = 0
        obj.reparentTo(self.itemFrame.getCanvas())
        obj.bind(DGG.B1PRESS, self.dragStart, [obj])
        obj.bind(DGG.B1RELEASE, self.dragStop)
        obj.bind(DGG.ENTER, self.inObject, [obj])
        obj.bind(DGG.EXIT, self.outObject, [obj])
        return obj

    def updateList(self, items):
        for item in self.itemList:
            item.destroy()
        i = 1
        j = 0
        pad = 0.2
        numItemsPerRow = 2
        itemWidth = 0.32
        itemHeight = 0.32
        # left = -(itemWidth * (numItemsPerRow/2.0)) - 0.16
        left = self.itemFrame.getX()  # + (itemWidth + 0.16)
        xStep = itemWidth + 0.13
        yStep = -(itemHeight + 0.13)
        top = 0.8 - (0.16 + pad)
        for item in items:
            self.itemList.append(self.__makeItem(item))
            x = left + i * xStep
            y = top + j * yStep
            self.itemList[-1].setPos(x, 0.0, y)
            if i == numItemsPerRow:
                i = 0
                j += 1
            i += 1
        if i == 1:
            j -= 1
        height = ((j) * -yStep) - 0.16
        # resize the canvas. This will make the scrollbars dis-/appear,
        # dependent on if the canvas is bigger than the frame size.
        self.itemFrame["canvasSize"] = (-0.6, 0.6, -height, 0.8)

    def inObject(self, element, event):
        # Can be used to highlight objects
        element["activeState"] = 1
        element.setActiveState()
        # print "over object"

    def outObject(self, element, event):
        # Can be used to unhighlight objects
        # element["state"] = 0
        element["activeState"] = 0
        element.setActiveState()

    def dragStart(self, element, event):
        print "start drag"
        taskMgr.remove("dragDropTask")
        vWidget2render2d = element.getPos(render2d)
        vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1])
        editVec = Vec3(vWidget2render2d - vMouse2render2d)
        t = taskMgr.add(self.dragTask, "dragDropTask")
        element.reparentTo(aspect2d)
        t.element = element
        t.editVec = editVec
        t.elementStartPos = element.getPos()

    def dragTask(self, state):
        mwn = base.mouseWatcherNode
        if mwn.hasMouse():
            vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1])
            newPos = vMouse2render2d + state.editVec
            state.element.setPos(render2d, newPos)
        return Task.cont

    def dragStop(self, event):
        print "stop drag with:", event
        isInArea = False

        t = taskMgr.getTasksNamed("dragDropTask")[0]
        # for dropArea in self.dropAreas:
        #    if self.isInBounds(event.getMouse(), dropArea["frameSize"], dropArea.getPos(render)):
        #        print "inside Area:", dropArea["text"], dropArea.getPos(render)
        #        isInArea = True
        #        t.element.setPos(dropArea.getPos(render))
        #        t.element.setX(t.element.getX() * self.ratio)
        #        #t.element.setX(t.element.getX() - t.element.getWidth() / 2.0)
        #        break

        if not isInArea:
            t.element.setPos(t.elementStartPos)
            t.element.reparentTo(self.itemFrame.getCanvas())
        taskMgr.remove("dragDropTask")

    def isInBounds(self, location, bounds, posShift=None):
        x = 0 if posShift is None else posShift.getX()
        y = 0 if posShift is None else posShift.getZ()

        left = x + bounds[0]
        right = x + bounds[1]
        bottom = y + bounds[2]
        top = y + bounds[3]

        # are we outside of the bounding box from the left
        if location[0] < left:
            return False
        # are we outside of the bounding box from the right
        if location[0] > right:
            return False
        # are we outside of the bounding box from the bottom
        if location[1] < bottom:
            return False
        # are we outside of the bounding box from the top
        if location[1] > top:
            return False
        # the location is inside the bbox
        return True
Example #18
0
class DeviceMonitor(DirectObject):
    def __init__(self, device):
        super().__init__()
        self.device = device
        self.create_panel()
        self.activate()
        self.hide()

    def activate(self):
        print("Device connected")
        print("  Name        : {}".format(self.device.name))
        print("  Type        : {}".format(self.device.device_class.name))
        print("  Manufacturer: {}".format(self.device.manufacturer))
        print("  ID          : {:04x}:{:04x}".format(self.device.vendor_id,
                                                     self.device.product_id))
        axis_names = [axis.axis.name for axis in self.device.axes]
        print("  Axes        : {} ({})".format(len(self.device.axes),
                                               ', '.join(axis_names)))
        button_names = [button.handle.name for button in self.device.buttons]
        print("  Buttons     : {} ({})".format(len(self.device.buttons),
                                               ', '.join(button_names)))

        base.attachInputDevice(self.device)

        self.task = base.taskMgr.add(
            self.update,
            "Monitor for {}".format(self.device.name),
            sort=10,
        )

    def deactivate(self):
        print("\"{}\" disconnected".format(self.device.name))
        base.taskMgr.remove(self.task)
        self.panel.detach_node()

    def create_panel(self):
        panel_width = base.a2dLeft * -0.25 + base.a2dRight
        scroll_bar_width = 0.08
        # NOTE: -0.001 because thanks to inaccuracy the vertical bar appears...
        canvas_width = panel_width - scroll_bar_width - 0.001
        canvas_height = base.a2dBottom - base.a2dTop

        self.panel = DirectScrolledFrame(
            frameSize=VBase4(
                0,
                panel_width,
                canvas_height,
                0,
            ),
            frameColor=VBase4(0.8, 0.8, 0.8, 1),
            canvasSize=VBase4(
                0,
                canvas_width,
                canvas_height,
                0,
            ),
            scrollBarWidth=scroll_bar_width,
            manageScrollBars=True,
            autoHideScrollBars=True,
            pos=(base.a2dLeft * 0.25, 0, base.a2dTop),
            parent=base.aspect2d,
        )
        panel_canvas = self.panel.getCanvas()
        offset = -0.0

        # Style sheets

        half_width_entry = dict(
            frameSize=VBase4(
                0,
                canvas_width / 2,
                -0.1,
                0,
            ),
            parent=panel_canvas,
            frameColor=VBase4(0.8, 0.8, 0.8, 1),
        )
        left_aligned_small_text = dict(
            text_align=TextNode.ALeft,
            text_scale=0.05,
            text_fg=VBase4(0,0,0,1),
            text_pos=(0.05, -0.06),
        )
        half_width_text_frame = dict(
            **half_width_entry,
            **left_aligned_small_text,
        )

        header = dict(
            frameSize=VBase4(
                0,
                canvas_width,
                -0.1,
                0,
            ),
            parent=panel_canvas,
            frameColor=VBase4(0.6, 0.6, 0.6, 1),
            text_align=TextNode.ALeft,
            text_scale=0.1,
            text_fg=VBase4(0,0,0,1),
            text_pos=(0.05, -0.075),
        )

        # Basic device data (name, device class, manufacturer, USB ID)

        self.device_header = DirectLabel(
            text="Device data",
            pos=(0, 0, offset),
            **header,
        )
        offset -= 0.1

        def add_data_entry(offset, label, text):
            self.name = DirectLabel(
                text=label,
                pos=(0, 0, offset),
                **half_width_text_frame,
            )
            self.name = DirectLabel(
                text=text,
                pos=(canvas_width / 2, 0, offset),
                **half_width_text_frame,
            )

        metadata = [
            ('Name', self.device.name),
            ('Device class', self.device.device_class.name),
            ('Manufacturer', self.device.manufacturer),
            ('USB ID',
             "{:04x}:{:04x}".format(
                 self.device.vendor_id,
                 self.device.product_id,
             ),
            ),
        ]
        for label, text in metadata:
            add_data_entry(offset, label, text)
            offset -= 0.1

        # Axes

        self.axis_sliders = []
        if len(self.device.axes) > 0:
            offset -= 0.1
            self.axes_header = DirectLabel(
                text="Axes",
                pos=(0, 0, offset),
                **header,
            )
            offset -= 0.1

            def add_axis(offset, axis_name):
                slider_width = canvas_width / 2
                label = DirectLabel(
                    text=axis_name,
                    **left_aligned_small_text,
                    pos=(0.05, 0, offset),
                    parent=panel_canvas,
                )
                slider = DirectSlider(
                    value=0.0,
                    range=(-1.0, 1.0),
                    state=DGG.DISABLED,
                    frameSize=VBase4(
                        0,
                        slider_width,
                        -0.1,
                        0,
                    ),
                    thumb_frameSize=VBase4(
                        0.0,
                        0.04,
                        -0.04,
                        0.04),
                    frameColor=VBase4(0.3, 0.3, 0.3, 1),
                    pos=(canvas_width - slider_width, 0, offset),
                    parent=panel_canvas,
                )
                return slider

            for axis in self.device.axes:
                axis_slider = add_axis(offset, axis.axis.name)
                self.axis_sliders.append(axis_slider)
                offset -= 0.1

        # Buttons

        self.button_buttons = []
        if len(self.device.buttons) > 0:
            offset -= 0.1
            self.buttons_header = DirectLabel(
                text="Buttons",
                pos=(0, 0, offset),
                **header,
            )
            offset -= 0.1

            def add_button(offset, button_name):
                button_width = canvas_width / 2
                label = DirectLabel(
                    text=button_name,
                    **left_aligned_small_text,
                    pos=(0.05, 0, offset),
                    parent=panel_canvas,
                )
                button = DirectFrame(
                    frameSize=VBase4(
                        0,
                        button_width,
                        -0.1,
                        0,
                    ),
                    text="",
                    text_align=TextNode.ACenter,
                    text_scale=0.05,
                    text_fg=VBase4(0,0,0,1),
                    text_pos=(button_width / 2, -0.06),
                    frameColor=VBase4(0.3, 0.3, 0.3, 1),
                    pos=(canvas_width - button_width, 0, offset),
                    parent=panel_canvas,
                )
                return button

            for i in range(len(self.device.buttons)):
                button_name = self.device.buttons[i].handle.name
                button_button = add_button(offset, button_name)
                self.button_buttons.append(button_button)
                offset -= 0.1

        # Vibration

        self.vibration = []
        if self.device.has_feature(InputDevice.Feature.vibration):
            offset -= 0.1
            self.vibration_header = DirectLabel(
                text="Vibration",
                pos=(0, 0, offset),
                **header,
            )
            offset -= 0.1

            def add_vibration(offset, axis_name, index):
                slider_width = canvas_width / 2
                label = DirectLabel(
                    text=axis_name,
                    **left_aligned_small_text,
                    pos=(0.05, 0, offset),
                    parent=panel_canvas,
                )
                slider = DirectSlider(
                    value=0.0,
                    range=(0.0, 1.0),
                    command=self.update_vibration,
                    frameSize=VBase4(
                        0,
                        slider_width,
                        -0.1,
                        0,
                    ),
                    thumb_frameSize=VBase4(
                        0.0,
                        0.04,
                        -0.04,
                        0.04),
                    frameColor=VBase4(0.3, 0.3, 0.3, 1),
                    pos=(canvas_width - slider_width, 0, offset),
                    parent=panel_canvas,
                )
                return slider

            for index, name in enumerate(["low frequency", "high frequency"]):
                self.vibration.append(add_vibration(offset, name, index))
                offset -= 0.1

        # Resize the panel's canvas to the widgets actually in it.
        if -offset > -canvas_height:
            self.panel['canvasSize'] = VBase4(
                0,
                canvas_width,
                offset,
                0,
            )
        self.panel.setCanvasSize()

    def show(self):
        # FIXME: Activate update task here, and deactivate it in hide()?
        self.panel.show()

    def hide(self):
        self.panel.hide()

    def update_vibration(self):
        low = self.vibration[0]['value']
        high = self.vibration[1]['value']
        self.device.set_vibration(low, high)

    def update(self, task):
        # FIXME: There needs to be a demo of events here, too.
        for idx, slider in enumerate(self.axis_sliders):
            slider["value"] = self.device.axes[idx].value
        for idx, button in enumerate(self.button_buttons):
            if self.device.buttons[idx].known:
                if self.device.buttons[idx].pressed:
                    button['frameColor'] = VBase4(0.0, 0.8, 0.0, 1)
                    button['text'] = "down"
                else:
                    button['frameColor'] = VBase4(0.3, 0.3, 0.3, 1)
                    button['text'] = "up"
            else:
                # State is InputDevice.S_unknown. This happens if the device
                # manager hasn't polled yet, and in some cases before a button
                # has been pressed after the program's start.
                button['frameColor'] = VBase4(0.8, 0.8, 0.0, 1)
                button['text'] = "unknown"
        return task.cont
class DirectTree(DirectObject):
  def __init__(self,
               pos=(0,0,0),
               parent=None,
               frameSize=(1,1),
               treeStructure=DirectTreeItem(),):
    if parent is None:
      parent = aspect2d
    self.treeStructure = treeStructure
    self.treeStructureNodes = dict()
    
    self.highlightedNodes = list()
    
    self.frameWidth = frameSize[0] #0.8
    self.frameHeight = frameSize[1] #1.5
    
    self.itemIndent = 0.05
    self.itemScale = 0.03
    self.itemTextScale = 1.2
    self.verticalSpacing = 0.0375
    self.__createTreeLines()
    
    self.childrenFrame = DirectScrolledFrame(
        parent=parent,pos=pos,
        relief=DGG.GROOVE,
        state=DGG.NORMAL, # to create a mouse watcher region
        manageScrollBars=0,
        enableEdit=0,
        #suppressMouse=1,
        sortOrder=1000,
        frameColor=(0,0,0,.7),
        borderWidth=(0.005,0.005),
        frameSize =(0, self.frameWidth, 0, self.frameHeight),
        canvasSize=(0, self.frameWidth-self.itemScale*2, 0, self.frameHeight),
        verticalScroll_frameSize   = [0,self.itemScale,0,1],
        horizontalScroll_frameSize = [0,1,0,self.itemScale],
      )
    self.childrenCanvas=self.childrenFrame.getCanvas().attachNewNode('myCanvas')
    self.childrenCanvas.setX(0.05)
    self.childrenCanvas.setZ(self.frameHeight-1) # some fix to have the list in the window
    
    self.accept(EVENT_DIRECTTREE_REFRESH, self.update)
  
  def destroy(self):
    self.treeStructure = DirectTreeItem()
    self.render()
    self.childrenFrame.destroy()
    #del self.treeStructureNodes
  
  def __createLine(self, length=1, color=(1,1,1,1), endColor=None):
    LS=LineSegs()
    LS.setColor(*color)
    LS.moveTo(0,0,0)
    LS.drawTo(length*1,0,0)
    node=LS.create()
    if endColor:
      LS.setVertexColor(1,*endColor)
    return node
  def __createTreeLines(self):
    # create horisontal tree line
    color=(1,0,0,.9)
    self.horizontalTreeLine=NodePath(self.__createLine(
      self.itemIndent+self.itemScale*.5,
      color,endColor=(1,1,1,.1)))
    self.horizontalTreeLine.setTwoSided(0,100)
    self.horizontalTreeLine.setTransparency(1)
    # create vertical tree line
    self.verticalTreeLine=NodePath(self.__createLine(
      self.verticalSpacing,color))
    self.verticalTreeLine.setR(90)
    self.verticalTreeLine.setTwoSided(0,100)
    self.verticalTreeLine.setTransparency(1)
  
  def render(self):
    ''' traverse the tree and update the visuals according to it
    '''
    for treeItem in self.treeStructure.getRec():
      # create nodes that have no visual elements
      if not treeItem in self.treeStructureNodes:
        treeNode = self.childrenCanvas.attachNewNode('')
        
        hor=self.horizontalTreeLine.instanceUnderNode(treeNode,'')
        vert=self.verticalTreeLine.instanceUnderNode(treeNode,'')
        vert.setZ(0.007)
        hor.setPos(-1.5*self.itemIndent,0,self.itemScale*.25)
        vert.setX(-.5*self.itemIndent)
        
        nodeButton = DirectButton(
            parent=treeNode,
            scale=self.itemScale,
            relief=DGG.FLAT,
            text_scale=self.itemTextScale,
            text_align=TextNode.ALeft,
            text=treeItem.name,
            rolloverSound=None,
            #clickSound=None,
          )
        nodeButton.bind(DGG.B1PRESS,treeItem.button1press)
        nodeButton.bind(DGG.B2PRESS,treeItem.button2press)
        nodeButton.bind(DGG.B3PRESS,treeItem.button3press)
        
        #treeButton = None
        #if len(treeItem.childrens) > 0:
        treeButton = DirectButton(
            parent=nodeButton,
            frameColor=(1,1,1,1),
            frameSize=(-.4,.4,-.4,.4),
            pos=(-.5*self.itemIndent/self.itemScale,0,.25),
            text='',
            text_pos=(-.1,-.22),
            text_scale=(1.6,1),
            text_fg=(0,0,0,1),
            enableEdit=0,
            command=treeItem.setOpen,
            sortOrder=1000,
            rolloverSound=None,
            #clickSound=None,
          )
        

        self.treeStructureNodes[treeItem] = [treeNode, nodeButton, treeButton, hor, vert]
    
    # destroy nodes no more used
    for treeItem in self.treeStructureNodes.keys()[:]:
      #treeItem = self.treeStructureNodes[treeName]
      if treeItem not in self.treeStructure.getRec():
        treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[treeItem]
        #nodeButton['text']=''
        nodeButton.unbind(DGG.B1PRESS)
        nodeButton.unbind(DGG.B2PRESS)
        nodeButton.unbind(DGG.B3PRESS)
        #nodeButton.detachNode()
        #nodeButton.removeNode()
        nodeButton.destroy()
        if treeButton:
          #treeButton['text']=''
          #treeButton['command']=None
          treeButton.detachNode()
          treeButton.removeNode()
        hor.detachNode()
        hor.removeNode()
        vert.detachNode()
        vert.removeNode()
        treeItem.destroy()
        #treeNode.detachNode()
        treeNode.removeNode()
        #treeNode.destroy()
        del self.treeStructureNodes[treeItem]
    
    frameHeight = len(self.treeStructureNodes) * self.verticalSpacing
    self.childrenFrame['canvasSize'] = (0, self.frameWidth-self.itemScale*2, 0, frameHeight)
    self.childrenCanvas.setZ(frameHeight-1)
  
  def highlight(self, selectedTreeNodes):
    for treeNode in self.highlightedNodes:
      treeNode.highlighted = False
    self.highlightedNodes = selectedTreeNodes
    for treeNode in self.highlightedNodes:
      treeNode.highlighted = True
    self.update()
  
  def update(self):
    ''' update the tree, updating the positions and hidden status of childrens
    '''
    idx = 0
    for treeItem in self.treeStructure.getRec():
      # show or hide the items
      treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[treeItem]
      if treeItem.getShow():
        treeNode.show()
        vert.show()
        if treeItem.parent: # dont show the horizontal line on the parent
          hor.show()
        else:
          hor.hide()
        idx += 1
      else:
        treeNode.hide()
        hor.hide()
        vert.hide()
      
      if len(treeItem.childrens) > 0:
        treeButton.show()
      else:
        treeButton.hide()
      
      if treeItem.highlighted:
        nodeButton['text_fg'] = (1,0,0,1)
      else:
        nodeButton['text_fg'] = (0,0,0,1)
      
      # update the vertical position of the node
      treeNode.setPos(treeItem.getDepth()*self.itemIndent,0,1-idx*self.verticalSpacing)
      
      # if the tree element has a treebutton (if it has childrens), update the +/-
      if treeButton:
        # update the text for the open/close button
        tag = ['+','-'][treeItem.open]
        treeButton['text']=tag
      
      # calculate length to the last children with the same depth as this treeitem
      # this gives the length of the vertical line
      c = -1; i = 0; treeItemDepth = treeItem.getDepth()
      for recItem in treeItem.getRec():
        if recItem.getShow():
          c+=1
        if recItem.getDepth() == treeItemDepth+1:
          i = c
      vert.setSz(i)
Example #20
0
class DeviceConnectivityMonitor(DirectObject):
    def __init__(self):
        super().__init__()
        self.mgr = InputDeviceManager.get_global_ptr()
        self.create_device_menu()

        self.devices = {}
        for device in self.mgr.get_devices():
            self.connect_device(device)

        self.accept("connect-device", self.connect_device)
        self.accept("disconnect-device", self.disconnect_device)

    def create_device_menu(self):
        self.current_panel = None
        self.buttons = {}
        self.devices_frame = DirectScrolledFrame(
            frameSize=VBase4(
                0,
                base.a2dLeft*-0.75,
                base.a2dBottom - base.a2dTop,
                0,
            ),
            frameColor=VBase4(0, 0, 0.25, 1.0),
            canvasSize=VBase4(
                0,
                base.a2dLeft*-0.75,
                0,
                0,
            ),
            scrollBarWidth=0.08,
            manageScrollBars=True,
            autoHideScrollBars=True,
            pos=(base.a2dLeft, 0, base.a2dTop),
            parent=base.aspect2d,
        )

        self.devices_frame.setCanvasSize()

    def create_menu_button(self, device):
        button = DirectButton(
            command=self.switch_to_panel,
            extraArgs=[device],
            text=device.name,
            text_scale=0.05,
            text_align=TextNode.ALeft,
            text_fg=VBase4(0.0, 0.0, 0.0, 1.0),
            text_pos=Vec2(0.01, base.a2dBottom / 10.0),
            relief=1,
            pad=Vec2(0.01, 0.01),
            frameColor=VBase4(0.8, 0.8, 0.8, 1.0),
            frameSize=VBase4(
                0.0,
                base.a2dLeft*-0.75 - 0.081,  # 0.08=Scrollbar, 0.001=inaccuracy
                base.a2dBottom / 5.0,
                0.0,
            ),
            parent=self.devices_frame.getCanvas(),
        )
        self.buttons[device] = button

    def destroy_menu_button(self, device):
        self.buttons[device].detach_node()
        del self.buttons[device]

    def refresh_device_menu(self):
        self.devices_frame['canvasSize'] = VBase4(
            0,
            base.a2dLeft*-0.75,
            base.a2dBottom / 5.0 * len(self.buttons),
            0,
        )
        self.devices_frame.setCanvasSize()
        sorted_buttons = sorted(self.buttons.items(), key=lambda i: i[0].name)
        for idx, (dev, button) in enumerate(sorted_buttons):
            button.set_pos(
                0,
                0,
                (base.a2dBottom / 5.0) * idx,
            )

    def switch_to_panel(self, device):
        if self.current_panel is not None:
            self.devices[self.current_panel].hide()
        self.current_panel = device
        self.devices[self.current_panel].show()

    def connect_device(self, device):
        self.devices[device] = DeviceMonitor(device)
        self.switch_to_panel(device)
        self.create_menu_button(device)
        self.refresh_device_menu()

    def disconnect_device(self, device):
        self.devices[device].deactivate()
        del self.devices[device]
        if self.current_panel == device:
            self.current_panel = None
            if len(self.devices) > 0:
                active_device = sorted(
                    self.devices.keys(),
                    key=lambda d: d.name,
                )[0]
                self.switch_to_panel(active_device)

        self.destroy_menu_button(device)
        self.refresh_device_menu()
Example #21
0
class HostMenu(DirectObject):
    def __init__(self):
        self.defaultBtnMap = base.loader.loadModel("gui/button_map")
        self.buttonGeom = (
            self.defaultBtnMap.find("**/button_ready"),
            self.defaultBtnMap.find("**/button_click"),
            self.defaultBtnMap.find("**/button_rollover"),
            self.defaultBtnMap.find("**/button_disabled"))

        defaultFont = loader.loadFont('gui/eufm10.ttf')

        self.logFrame = DirectScrolledFrame(
            canvasSize = (0, base.a2dRight * 2, -5, 0),
            frameSize = (0, base.a2dRight * 2,
                (base.a2dBottom+.2) * 2, 0),
            frameColor = (0.1, 0.1, 0.1, 1))
        self.logFrame.reparentTo(base.a2dTopLeft)

        # create the info and server debug output
        self.textscale = 0.1
        self.txtinfo = OnscreenText(
            scale = self.textscale,
            pos = (0.1, -0.1),
            text = "",
            align = TextNode.ALeft,
            fg = (0.1,1.0,0.15,1),
            bg = (0, 0, 0, 0),
            shadow = (0, 0, 0, 1),
            shadowOffset = (-0.02, -0.02))
        self.txtinfo.setTransparency(1)
        self.txtinfo.reparentTo(self.logFrame.getCanvas())

        # create a close Server button
        self.btnBackPos = Vec3(0.4, 0, 0.2)
        self.btnBackScale = 0.25
        self.btnBack = DirectButton(
            # Scale and position
            scale = self.btnBackScale,
            pos = self.btnBackPos,
            # Text
            text = "Quit Server",
            text_scale = 0.45,
            text_pos = (0, -0.1),
            text_fg = (0.82,0.85,0.87,1),
            text_shadow = (0, 0, 0, 1),
            text_shadowOffset = (-0.02, -0.02),
            text_font = defaultFont,
            # Frame
            geom = self.buttonGeom,
            frameColor = (0, 0, 0, 0),
            relief = 0,
            pressEffect = False,
            # Functionality
            command = self.back,
            rolloverSound = None,
            clickSound = None)
        self.btnBack.setTransparency(1)
        self.btnBack.reparentTo(base.a2dBottomLeft)

        # catch window resizes and recalculate the aspectration
        self.accept("window-event", self.recalcAspectRatio)
        self.accept("addLog", self.addLog)

    def show(self):
        self.logFrame.show()
        self.btnBack.show()

    def hide(self):
        self.logFrame.hide()
        self.btnBack.hide()

    def back(self):
        self.hide()
        base.messenger.send("stop_server")
        self.addLog("Quit Server!")

    def addLog(self, text):
        self.txtinfo.appendText(text + "\n")
        textbounds = self.txtinfo.getTightBounds()
        self.logFrame["canvasSize"] = (0, textbounds[1].getX(),
                                        textbounds[0].getZ(), 0)

    def recalcAspectRatio(self, window):
        """get the new aspect ratio to resize the mainframe"""
        # set the mainframe size to the window borders again
        self.logFrame["frameSize"] = (
            0, base.a2dRight * 2,
            (base.a2dBottom+.2) * 2, 0)
Example #22
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)