Ejemplo n.º 1
0
class InventorySlotButton():
    
    def __init__(self, slotIndexX, slotIndexY, xCoord, yCoord, padding, x, y, inventorySlot, parentInventory, onClickFunction):
        self.xIndex = slotIndexX                    # The x index of the button in the inventory
        self.yIndex = slotIndexY                    # The y index of the button in the inventory
        self.button = None                          # The DirectButton
        self.inventorySlot = inventorySlot          # The slot this button represents
        self.parentInventory = parentInventory      # The region this slot belongs to
        
        self.LoadContent(x, y, xCoord, yCoord, padding, onClickFunction)
        
    def LoadContent(self, x, y, xCoord, yCoord, padding, onClickFunction):
        egg = 'inventorySlot'
        up = ''.join([egg, '-up'])
        over = ''.join([egg, '-over'])
        maps = loader.loadModel("Assets/Images/Inventory/%s" % ('inventorySlot'))
        self.button = DirectButton(geom = (maps.find('**/%s' % (up)),
                         maps.find('**/%s' % (over)),
                         maps.find('**/%s' % (over)),
                         maps.find('**/%s' % (up))),
                         command = onClickFunction,
                         extraArgs = [self],
                         pressEffect = 0,
                         relief = None,
                         rolloverSound = None, 
                         clickSound = None,
                         scale = (128.0/1024.0, 1, 128.0/1024.0))
        
        pos = Globals.ConvertFromImageAbsoluteToAspect2D(xCoord + x * padding, yCoord + y * padding, 1024)
        self.button.setPos(pos[0], 0, pos[1])
        
    def ReparentTo(self, node):
        self.button.reparentTo(node)
        
    def GetPos(self):
        return self.button.getPos()
    
    def GetParentInventory(self):
        return self.parentInventory
    
    def GetInventorySlot(self):
        return self.inventorySlot
    
    def GetSlotIndices(self):
        return [self.xIndex, self.yIndex]
Ejemplo n.º 2
0
class PlacerTool3D(DirectFrame):
    ORIGINAL_SCALE = (1.0, 1.0, 1.0)
    MINIMIZED_SCALE = (0.85, 1.0, 0.15)
    ORIG_DRAG_BUTTON_POS = (0.37, 0.0, 0.37)
    MINI_DRAG_BUTTON_POS = (0.37, 0.0, 0.03)
    ORIG_MINI_BUTTON_POS = (0.29, 0.0, 0.37)
    MINI_MINI_BUTTON_POS = (0.29, 0.0, 0.03)
    ORIG_NAME_POS = (-0.39, 0.0, 0.27)
    MINI_NAME_POS = (-0.39, 0.0, 0.0)

    def __init__(self,
                 target,
                 increment=0.01,
                 hprIncrement=1.0,
                 parent=aspect2d,
                 pos=(0.0, 0.0, 0.0)):
        DirectFrame.__init__(self, parent)
        self.target = target
        self.increment = increment
        self.minimized = False
        self.mainFrame = DirectFrame(
            parent=self,
            relief=None,
            geom=DGG.getDefaultDialogGeom(),
            geom_color=(1, 1, 0.75, 1),
            geom_scale=self.ORIGINAL_SCALE,
            pos=pos,
        )
        # Arrow gui (preload)
        gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui.bam')
        # Set Bins
        self.mainFrame.setBin('gui-popup', 0)
        # Name
        name = self.target.getName()
        self.nameLabel = TTLabel(self.mainFrame,
                                 text='Target: %s' % name,
                                 pos=self.ORIG_NAME_POS,
                                 text_align=TextNode.ALeft,
                                 text_wordwrap=13)
        # Pos
        pos = self.target.getPos()
        self.posLabel = TTLabel(self.mainFrame,
                                text='Position: ',
                                pos=(-0.39, 0.0, 0.055),
                                text_align=TextNode.ALeft)
        self.xPosSpinner = PlacerToolSpinner(self.mainFrame,
                                             value=pos[0],
                                             pos=(-0.085, 0.0, 0.06),
                                             increment=increment,
                                             callback=self.handleXChange)
        self.yPosSpinner = PlacerToolSpinner(self.mainFrame,
                                             value=pos[1],
                                             pos=(0.1, 0.0, 0.06),
                                             increment=increment,
                                             callback=self.handleYChange)
        self.zPosSpinner = PlacerToolSpinner(self.mainFrame,
                                             value=pos[2],
                                             pos=(0.28, 0.0, 0.06),
                                             increment=increment,
                                             callback=self.handleZChange)
        # hpr
        hpr = self.target.getHpr()
        self.hprLabel = TTLabel(self.mainFrame,
                                text='HPR: ',
                                pos=(-0.39, 0.0, -0.19),
                                text_align=TextNode.ALeft)
        self.hSpinner = PlacerToolSpinner(self.mainFrame,
                                          value=hpr[0],
                                          pos=(-0.085, 0.0, -0.195),
                                          increment=hprIncrement,
                                          callback=self.handleHChange)
        self.pSpinner = PlacerToolSpinner(self.mainFrame,
                                          value=hpr[1],
                                          pos=(0.1, 0.0, -0.195),
                                          increment=hprIncrement,
                                          callback=self.handlePChange)
        self.rSpinner = PlacerToolSpinner(self.mainFrame,
                                          value=hpr[2],
                                          pos=(0.28, 0.0, -0.195),
                                          increment=hprIncrement,
                                          callback=self.handleRChange)
        # scale
        scale = [round(s, 3) for s in self.target.getScale()]
        self.scaleLabel = TTLabel(self.mainFrame,
                                  text='Scale: ',
                                  pos=(-0.39, 0.0, -0.4),
                                  text_align=TextNode.ALeft)

        self.sxSpinner = PlacerToolSpinner(self.mainFrame,
                                           value=hpr[0],
                                           pos=(-0.085, 0.0, -0.4),
                                           increment=increment,
                                           callback=self.handleSxChange)
        self.sySpinner = PlacerToolSpinner(self.mainFrame,
                                           value=hpr[1],
                                           pos=(0.1, 0.0, -0.4),
                                           increment=increment,
                                           callback=self.handleSyChange)
        self.szSpinner = PlacerToolSpinner(self.mainFrame,
                                           value=hpr[2],
                                           pos=(0.28, 0.0, -0.4),
                                           increment=increment,
                                           callback=self.handleSzChange)

        gui.removeNode()
        gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_nameShop')
        thumb = gui.find('**/tt_t_gui_mat_namePanelCircle')
        self.dragButton = DirectButton(self.mainFrame,
                                       relief=None,
                                       image=thumb,
                                       image_scale=(0.5, 0.5, 0.5),
                                       pos=self.ORIG_DRAG_BUTTON_POS)
        self.minimizeButton = DirectButton(self.mainFrame,
                                           relief=None,
                                           image=thumb,
                                           image_scale=(0.5, 0.5, 0.5),
                                           image_color=(0.0, 0.0, 0.65, 1.0),
                                           pos=self.ORIG_MINI_BUTTON_POS,
                                           command=self.toggleMinimize,
                                           extraArgs=[])
        self.dragButton.bind(DGG.B1PRESS, self.onPress)
        if target is not None:
            self.setTarget(target)

    def destroy(self):
        self.target = None
        messenger.send('placer-destroyed', [self])
        DirectFrame.destroy(self)

    def setTarget(self, target):
        self.target = target
        name = self.target.getName()
        scale = [round(s, 3) for s in self.target.getScale()]
        x, y, z = self.target.getPos()
        h, p, r = self.target.getHpr()
        sx, sy, sz = self.target.getScale()
        self.nameLabel['text'] = 'Target: %s' % name
        self.xPosSpinner.setValue(x)
        self.yPosSpinner.setValue(y)
        self.zPosSpinner.setValue(z)
        self.hSpinner.setValue(h)
        self.pSpinner.setValue(p)
        self.rSpinner.setValue(r)
        self.sxSpinner.setValue(sx)
        self.sySpinner.setValue(sy)
        self.szSpinner.setValue(sz)

    def handleXChange(self, value):
        self.changeTargetPos(0, value)

    def handleYChange(self, value):
        self.changeTargetPos(1, value)

    def handleZChange(self, value):
        self.changeTargetPos(2, value)

    def handleHChange(self, value):
        self.changeTargetHpr(0, value)

    def handlePChange(self, value):
        self.changeTargetHpr(1, value)

    def handleRChange(self, value):
        self.changeTargetHpr(2, value)

    def handleSxChange(self, value):
        self.changeTargetScale(0, value)

    def handleSyChange(self, value):
        self.changeTargetScale(1, value)

    def handleSzChange(self, value):
        self.changeTargetScale(2, value)

    def changeTargetPos(self, index, value):
        pos = self.target.getPos()
        pos[index] = float(value)
        self.target.setPos(pos)

    def changeTargetHpr(self, index, value):
        hpr = self.target.getHpr()
        hpr[index] = float(value)
        self.target.setHpr(hpr)

    def changeTargetScale(self, index, value):
        pos = self.target.getScale()
        pos[index] = float(value)
        self.target.setScale(pos)

    def toggleMinimize(self):
        if self.minimized:
            self.maximize()
        else:
            self.minimize()

    def minimize(self):
        self.minimized = True
        self.mainFrame['geom_scale'] = self.MINIMIZED_SCALE
        self.nameLabel.setPos(self.MINI_NAME_POS)
        self.dragButton.setPos(self.MINI_DRAG_BUTTON_POS)
        self.minimizeButton.setPos(self.MINI_MINI_BUTTON_POS)
        self.posLabel.hide()
        self.xPosSpinner.hide()
        self.yPosSpinner.hide()
        self.zPosSpinner.hide()
        self.hprLabel.hide()
        self.hSpinner.hide()
        self.pSpinner.hide()
        self.rSpinner.hide()
        self.scaleLabel.hide()
        self.setPos(0, 0, 0)

    def maximize(self):
        self.minimized = False
        self.mainFrame['geom_scale'] = self.ORIGINAL_SCALE
        self.nameLabel.setPos(self.ORIG_NAME_POS)
        self.dragButton.setPos(self.ORIG_DRAG_BUTTON_POS)
        self.minimizeButton.setPos(self.ORIG_MINI_BUTTON_POS)
        self.posLabel.show()
        self.xPosSpinner.show()
        self.yPosSpinner.show()
        self.zPosSpinner.show()
        self.hprLabel.show()
        self.hSpinner.show()
        self.pSpinner.show()
        self.rSpinner.show()
        self.scaleLabel.show()
        self.setPos(0, 0, 0)

    def onPress(self, e=None):
        self.accept('mouse1-up', self.onRelease)
        taskMgr.add(self.mouseMoverTask, '%s-mouseMoverTask' % self.id)

    def onRelease(self, e=None):
        self.ignore('mouse1-up')
        taskMgr.remove('%s-mouseMoverTask' % self.id)

    def mouseMoverTask(self, task):
        if base.mouseWatcherNode.hasMouse():
            mpos = base.mouseWatcherNode.getMouse()
            buttonPos = self.dragButton.getPos()
            newPos = (mpos[0] - buttonPos[0] / 2 - 0.02, 0,
                      mpos[1] - buttonPos[2])
            self.setPos(render2d, newPos)
        return task.cont
Ejemplo n.º 3
0
class Mediator(Receiver,FocusObserver,NodePathWrapper):
    """The singleton mediatorobject mediates the interaction between the
    StoryMap objects, receiving notifications and calling methods on StoryMap
    objects.

    """
    def __init__(self):

        # Create two story maps, 'Story Cards' which the user picks story cards
        # from, and 'My Story Map' in which the user constructs her story.
        self.storyCards = StoryMap(storyCardClass=FocusableChoosableStoryCard, 
                                   title="Story Cards")
        self.storyCards.reparentTo(zcanvas.home)
        self.storyCards.setScale(0.02)
        self.storyCards.setPos(-.5,0,.8)
        self.storyCards.fill()
        self.storyCards.added_behaviour = 'disable'
        
        self.myStoryMap = StoryMap(storyCardClass=FocusableEditableStoryCard, 
                                   title="My Story")
        self.myStoryMap.reparentTo(zcanvas.home)
        self.myStoryMap.setScale(0.02)
        self.myStoryMap.setPos(-.5,0,-.1)
        self.myStoryMap.added_behaviour = 'remove'
        #self.myStoryMap.keep_sorted = True        
        #self.myStoryMap.np.showTightBounds()
        self.myStoryMap.auto_grow = True
               
        # Keyboard controls for saving, loading and exporting.
        #base.accept("f1",self.save)
        #base.accept("f2",self.load)
        #base.accept("f3",self.export)
        
        # Subscribe to some messages.
        self.acceptOnce('zoom done',zcanvas.message,["Right-click to zoom back out again."])
        self.accept('add',self.add)
        self.accept('remove',self.remove)

        # Frame along the bottom for Save, Load and Quit buttons.
        self.bottom_np = aspect2d.attachNewNode('bottom frame')
        height = 0.15
        self.bottom_np.setPos(-base.getAspectRatio(),0,-1-height)
        cm = CardMaker('bottom frame')
        cm.setFrame(0,2*base.getAspectRatio(),0,height)
        self.bottom_np.attachNewNode(cm.generate())
        self.bottom_np.setTransparency(TransparencyAttrib.MAlpha)
        self.bottom_np.setColor(.1,.1,.1,.7)
        self.bottom_hbox = HBoxList(margin=1)
        self.bottom_hbox.reparentTo(self.bottom_np)
        self.bottom_hbox.setPos(0,0,height-0.03)
        self.bottom_hbox.setScale(.1)    
        self.save_button = DirectButton(text="Save",command=self.save)
        b = Box()
        b.fill(self.save_button)
        self.bottom_hbox.append(b)
        self.load_button = DirectButton(text="Load",command=self.load)
        b = Box()
        b.fill(self.load_button)
        self.bottom_hbox.append(b)
        # Interval that slides the frame onto the screen.
        self.bottom_interval = LerpPosInterval(
                            self.bottom_np,
                            duration=1,
                            pos=Point3(-base.getAspectRatio(),0,-1),
                            startPos=Point3(-base.getAspectRatio(),0,-1-height),
                            other=None,
                            blendType='easeInOut',
                            bakeInStart=1,
                            fluid=0,
                            name=None)
        self.bottom_reverse_interval = LerpPosInterval(
                                 self.bottom_np,
                                 duration=1,
                                 pos=Point3(-base.getAspectRatio(),0,-1-height),
                                 startPos=Point3(-base.getAspectRatio(),0,-1),
                                 other=None,
                                 blendType='easeInOut',
                                 bakeInStart=1,
                                 fluid=0,
                                 name=None)
        self.bottom_frame_is_active = False

        # Frame along the right for story cards.
        self.right_np = aspect2d.attachNewNode('right frame')
        width = 0.14*base.getAspectRatio()
        self.right_np.setPos(base.getAspectRatio()+width,0,1)
        cm = CardMaker('right frame')
        cm.setFrame(-width,0,-2,0)
        self.right_np.attachNewNode(cm.generate())
        self.right_np.setTransparency(TransparencyAttrib.MAlpha)
        self.right_np.setColor(.1,.1,.1,.7)
        self.right_vbox = Stack()
        self.right_vbox.reparentTo(self.right_np)
        self.right_vbox.setPos(-width+0.035,0,-0.06)
        self.right_vbox.setScale(.02)
        # Interval that slides the frame onto the screen.
        self.right_interval = LerpPosInterval(
                               self.right_np,
                               duration=1,
                               pos=Point3(base.getAspectRatio(),0,1),
                               startPos=Point3(base.getAspectRatio()+width,0,1),
                               other=None,
                               blendType='easeInOut',
                               bakeInStart=1,
                               fluid=0,
                               name=None)
        self.right_reverse_interval = LerpPosInterval(
                                    self.right_np,
                                    duration=1,
                                    pos=Point3(base.getAspectRatio()+width,0,1),
                                    startPos=Point3(base.getAspectRatio(),0,1),
                                    other=None,
                                    blendType='easeInOut',
                                    bakeInStart=1,
                                    fluid=0,
                                    name=None)
        self.right_frame_is_active = False

        # Task that watches for the mouse going to the screen edges and slides
        # the frames onscreen when it does.
        self.prev_x = None
        self.prev_y = None
        taskMgr.add(self.task,'Mediator mouse watcher task')

        NodePathWrapper.__init__(self)
        FocusObserver.__init__(self)

    def enterNone(self):
        """Viewport focus has changed to None."""
        # Make the title of 'My Story Map' editable.
        self.myStoryMap.title['state'] = DGG.NORMAL
    def exitNone(self):
        """Undo any changes made by enterNone."""
        self.myStoryMap.title['state'] = DGG.DISABLED

    def task(self,task):
        if base.mouseWatcherNode.hasMouse():
            x=base.mouseWatcherNode.getMouseX()
            y=base.mouseWatcherNode.getMouseY()                        
            if y <= -0.87 and self.prev_y > -0.87:
                # The mouse has just moved into the bottom frame's area.
                self.activate_bottom_frame()
            elif y > -0.87 and self.prev_y <= -0.87:
                # The mouse has just moved out of the bottom frame's area.
                self.deactivate_bottom_frame()
            self.prev_y = y
            if x >= 0.8 and self.prev_x < 0.8:
                # The mouse has just moved into the right frame's area.
                self.activate_right_frame()
            elif x < 0.8 and self.prev_x >= 0.8:
                # The mouse has just moved out of the right frame's area.
                self.deactivate_right_frame()
            self.prev_x = x
        return task.cont

    def activate_bottom_frame(self):
        
        if not self.bottom_frame_is_active:
            self.bottom_interval.start()
            self.bottom_frame_is_active = True

    def deactivate_bottom_frame(self):

        if self.bottom_frame_is_active:
            self.bottom_reverse_interval.start()
            self.bottom_frame_is_active = False

    def activate_right_frame(self):        
        if not self.right_frame_is_active:
            self.right_interval.start()
            self.right_frame_is_active = True

    def deactivate_right_frame(self):
        if self.right_frame_is_active:
            self.right_reverse_interval.start()
            self.right_frame_is_active = False

    def add(self,card):
        # The Add button was pressed on one of the StoryCards in self.storyCards
        for box in self.right_vbox:
            if box.contents is None:
                box.fill(card)
                # self.activate_right_frame()
                return
        zcanvas.message('The stack is full!\nDrag another card from the stack first.')
        
    def remove(self,editableCard):
        # The Remove button was pressed on one of the StoryCards in
        # self.myStoryMap
        editableCard.getPythonTag('box').empty()
        for choosableCard in self.storyCards.items():
            if choosableCard.function == editableCard.function:
                choosableCard.enable()
                return

    # Implement the Originator interface of the memento design pattern. (For
    # saving and loading.)
    class Memento:
        """A passive class that stores the state of a Mediator object."""    
        def __init__(self, storycards, mystorymap, stack):
            # MediatorMemento just holds mementos for mediator's two StoryMap 
            # objects.
            self.storycards = storycards
            self.mystorymap = mystorymap    
            self.stack = stack
        def __str__(self):
            return self.mystorymap.__str__()
    
    def create_memento(self):
        """Return a memento object holding the current internal state of this
        object."""

        return Mediator.Memento(self.storyCards.create_memento(), 
                                self.myStoryMap.create_memento(),
                                self.right_vbox.create_memento())

    def restore_memento(self,memento):
        """Restore the internal state of this object to that held by the given
        memento."""

        self.storyCards.restore_memento(memento.storycards)
        self.myStoryMap.restore_memento(memento.mystorymap)
        self.right_vbox.restore_memento(memento.stack)

    # Implement the Caretaker interface of the memento design pattern. (For
    # saving and loading.)
    def save(self):
        """Save the current state of the application to file."""
        memento = self.create_memento()
        import datetime
        f = open(str(datetime.datetime.now()).replace(' ','_')+'.saved_story','w')
        cPickle.dump(memento,f)
        f.close()
        zcanvas.message("Saved!")

    def _load(self,args):
        self.load_list.removeNode()
        f = open(args,'r')
        memento = cPickle.load(f)
        f.close()
        self.restore_memento(memento)        
        taskMgr.doMethodLater(1, zcanvas.message, 'Welcome Message', extraArgs = ["Loaded!"])

    def load(self):
        """Restore the current state of the application from file."""
        dir = '.'
        ext = '.saved_story'
        saved_stories = [f for f in os.listdir(dir) if os.path.isfile(os.path.join(dir,f)) and f.endswith(ext)]
        saved_stories.sort()
        
        from direct.gui.DirectGui import DirectScrolledList,DirectButton
        labels = []
        for saved_story in saved_stories:
            filename,ext = os.path.splitext(saved_story)
            l = DirectButton(text=filename, scale=0.05, command=self._load, extraArgs=[saved_story])
            labels.append(l)                
        self.load_list = DirectScrolledList(
            decButton_pos= (0.35, 0, 0.53),
            decButton_text = "/\\",
            decButton_text_scale = 0.04,
            decButton_borderWidth = (0.005, 0.005),
        
            incButton_pos= (0.35, 0, -0.02),
            incButton_text = "\\/",
            incButton_text_scale = 0.04,
            incButton_borderWidth = (0.005, 0.005),
        
            #frameSize = (0.0, 0.7, -0.05, 0.59),
            #frameColor = (1,0,0,0.5),
            pos = self.load_button.getPos(aspect2d),
            items = labels,
            numItemsVisible = 4,
            forceHeight = 0.11,
            itemFrame_frameSize = (-0.3, 0.3, -0.37, 0.11),
            itemFrame_pos = (0.35, 0, 0.4),
            )
                                
    def export(self):
        """Export the current story to a text file."""
        memento = self.create_memento()
        try:
            f = open("story.txt", "w")
            try:
                f.write(memento.__str__())
            finally:
                f.close()
        except IOError:
            print 'IOError while exporting story!'    
Ejemplo n.º 4
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))
Ejemplo n.º 5
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))
Ejemplo n.º 6
0
class Mediator(Receiver, FocusObserver, NodePathWrapper):
    """The singleton mediatorobject mediates the interaction between the
    StoryMap objects, receiving notifications and calling methods on StoryMap
    objects.

    """
    def __init__(self):

        # Create two story maps, 'Story Cards' which the user picks story cards
        # from, and 'My Story Map' in which the user constructs her story.
        self.storyCards = StoryMap(storyCardClass=FocusableChoosableStoryCard,
                                   title="Story Cards")
        self.storyCards.reparentTo(zcanvas.home)
        self.storyCards.setScale(0.02)
        self.storyCards.setPos(-.5, 0, .8)
        self.storyCards.fill()
        self.storyCards.added_behaviour = 'disable'

        self.myStoryMap = StoryMap(storyCardClass=FocusableEditableStoryCard,
                                   title="My Story")
        self.myStoryMap.reparentTo(zcanvas.home)
        self.myStoryMap.setScale(0.02)
        self.myStoryMap.setPos(-.5, 0, -.1)
        self.myStoryMap.added_behaviour = 'remove'
        #self.myStoryMap.keep_sorted = True
        #self.myStoryMap.np.showTightBounds()
        self.myStoryMap.auto_grow = True

        # Keyboard controls for saving, loading and exporting.
        #base.accept("f1",self.save)
        #base.accept("f2",self.load)
        #base.accept("f3",self.export)

        # Subscribe to some messages.
        self.acceptOnce('zoom done', zcanvas.message,
                        ["Right-click to zoom back out again."])
        self.accept('add', self.add)
        self.accept('remove', self.remove)

        # Frame along the bottom for Save, Load and Quit buttons.
        self.bottom_np = aspect2d.attachNewNode('bottom frame')
        height = 0.15
        self.bottom_np.setPos(-base.getAspectRatio(), 0, -1 - height)
        cm = CardMaker('bottom frame')
        cm.setFrame(0, 2 * base.getAspectRatio(), 0, height)
        self.bottom_np.attachNewNode(cm.generate())
        self.bottom_np.setTransparency(TransparencyAttrib.MAlpha)
        self.bottom_np.setColor(.1, .1, .1, .7)
        self.bottom_hbox = HBoxList(margin=1)
        self.bottom_hbox.reparentTo(self.bottom_np)
        self.bottom_hbox.setPos(0, 0, height - 0.03)
        self.bottom_hbox.setScale(.1)
        self.save_button = DirectButton(text="Save", command=self.save)
        b = Box()
        b.fill(self.save_button)
        self.bottom_hbox.append(b)
        self.load_button = DirectButton(text="Load", command=self.load)
        b = Box()
        b.fill(self.load_button)
        self.bottom_hbox.append(b)
        # Interval that slides the frame onto the screen.
        self.bottom_interval = LerpPosInterval(
            self.bottom_np,
            duration=1,
            pos=Point3(-base.getAspectRatio(), 0, -1),
            startPos=Point3(-base.getAspectRatio(), 0, -1 - height),
            other=None,
            blendType='easeInOut',
            bakeInStart=1,
            fluid=0,
            name=None)
        self.bottom_reverse_interval = LerpPosInterval(
            self.bottom_np,
            duration=1,
            pos=Point3(-base.getAspectRatio(), 0, -1 - height),
            startPos=Point3(-base.getAspectRatio(), 0, -1),
            other=None,
            blendType='easeInOut',
            bakeInStart=1,
            fluid=0,
            name=None)
        self.bottom_frame_is_active = False

        # Frame along the right for story cards.
        self.right_np = aspect2d.attachNewNode('right frame')
        width = 0.14 * base.getAspectRatio()
        self.right_np.setPos(base.getAspectRatio() + width, 0, 1)
        cm = CardMaker('right frame')
        cm.setFrame(-width, 0, -2, 0)
        self.right_np.attachNewNode(cm.generate())
        self.right_np.setTransparency(TransparencyAttrib.MAlpha)
        self.right_np.setColor(.1, .1, .1, .7)
        self.right_vbox = Stack()
        self.right_vbox.reparentTo(self.right_np)
        self.right_vbox.setPos(-width + 0.035, 0, -0.06)
        self.right_vbox.setScale(.02)
        # Interval that slides the frame onto the screen.
        self.right_interval = LerpPosInterval(
            self.right_np,
            duration=1,
            pos=Point3(base.getAspectRatio(), 0, 1),
            startPos=Point3(base.getAspectRatio() + width, 0, 1),
            other=None,
            blendType='easeInOut',
            bakeInStart=1,
            fluid=0,
            name=None)
        self.right_reverse_interval = LerpPosInterval(
            self.right_np,
            duration=1,
            pos=Point3(base.getAspectRatio() + width, 0, 1),
            startPos=Point3(base.getAspectRatio(), 0, 1),
            other=None,
            blendType='easeInOut',
            bakeInStart=1,
            fluid=0,
            name=None)
        self.right_frame_is_active = False

        # Task that watches for the mouse going to the screen edges and slides
        # the frames onscreen when it does.
        self.prev_x = None
        self.prev_y = None
        taskMgr.add(self.task, 'Mediator mouse watcher task')

        NodePathWrapper.__init__(self)
        FocusObserver.__init__(self)

    def enterNone(self):
        """Viewport focus has changed to None."""
        # Make the title of 'My Story Map' editable.
        self.myStoryMap.title['state'] = DGG.NORMAL

    def exitNone(self):
        """Undo any changes made by enterNone."""
        self.myStoryMap.title['state'] = DGG.DISABLED

    def task(self, task):
        if base.mouseWatcherNode.hasMouse():
            x = base.mouseWatcherNode.getMouseX()
            y = base.mouseWatcherNode.getMouseY()
            if y <= -0.87 and self.prev_y > -0.87:
                # The mouse has just moved into the bottom frame's area.
                self.activate_bottom_frame()
            elif y > -0.87 and self.prev_y <= -0.87:
                # The mouse has just moved out of the bottom frame's area.
                self.deactivate_bottom_frame()
            self.prev_y = y
            if x >= 0.8 and self.prev_x < 0.8:
                # The mouse has just moved into the right frame's area.
                self.activate_right_frame()
            elif x < 0.8 and self.prev_x >= 0.8:
                # The mouse has just moved out of the right frame's area.
                self.deactivate_right_frame()
            self.prev_x = x
        return task.cont

    def activate_bottom_frame(self):

        if not self.bottom_frame_is_active:
            self.bottom_interval.start()
            self.bottom_frame_is_active = True

    def deactivate_bottom_frame(self):

        if self.bottom_frame_is_active:
            self.bottom_reverse_interval.start()
            self.bottom_frame_is_active = False

    def activate_right_frame(self):
        if not self.right_frame_is_active:
            self.right_interval.start()
            self.right_frame_is_active = True

    def deactivate_right_frame(self):
        if self.right_frame_is_active:
            self.right_reverse_interval.start()
            self.right_frame_is_active = False

    def add(self, card):
        # The Add button was pressed on one of the StoryCards in self.storyCards
        for box in self.right_vbox:
            if box.contents is None:
                box.fill(card)
                # self.activate_right_frame()
                return
        zcanvas.message(
            'The stack is full!\nDrag another card from the stack first.')

    def remove(self, editableCard):
        # The Remove button was pressed on one of the StoryCards in
        # self.myStoryMap
        editableCard.getPythonTag('box').empty()
        for choosableCard in self.storyCards.items():
            if choosableCard.function == editableCard.function:
                choosableCard.enable()
                return

    # Implement the Originator interface of the memento design pattern. (For
    # saving and loading.)
    class Memento:
        """A passive class that stores the state of a Mediator object."""
        def __init__(self, storycards, mystorymap, stack):
            # MediatorMemento just holds mementos for mediator's two StoryMap
            # objects.
            self.storycards = storycards
            self.mystorymap = mystorymap
            self.stack = stack

        def __str__(self):
            return self.mystorymap.__str__()

    def create_memento(self):
        """Return a memento object holding the current internal state of this
        object."""

        return Mediator.Memento(self.storyCards.create_memento(),
                                self.myStoryMap.create_memento(),
                                self.right_vbox.create_memento())

    def restore_memento(self, memento):
        """Restore the internal state of this object to that held by the given
        memento."""

        self.storyCards.restore_memento(memento.storycards)
        self.myStoryMap.restore_memento(memento.mystorymap)
        self.right_vbox.restore_memento(memento.stack)

    # Implement the Caretaker interface of the memento design pattern. (For
    # saving and loading.)
    def save(self):
        """Save the current state of the application to file."""
        memento = self.create_memento()
        import datetime
        f = open(
            str(datetime.datetime.now()).replace(' ', '_') + '.saved_story',
            'w')
        cPickle.dump(memento, f)
        f.close()
        zcanvas.message("Saved!")

    def _load(self, args):
        self.load_list.removeNode()
        f = open(args, 'r')
        memento = cPickle.load(f)
        f.close()
        self.restore_memento(memento)
        taskMgr.doMethodLater(1,
                              zcanvas.message,
                              'Welcome Message',
                              extraArgs=["Loaded!"])

    def load(self):
        """Restore the current state of the application from file."""
        dir = '.'
        ext = '.saved_story'
        saved_stories = [
            f for f in os.listdir(dir)
            if os.path.isfile(os.path.join(dir, f)) and f.endswith(ext)
        ]
        saved_stories.sort()

        from direct.gui.DirectGui import DirectScrolledList, DirectButton
        labels = []
        for saved_story in saved_stories:
            filename, ext = os.path.splitext(saved_story)
            l = DirectButton(text=filename,
                             scale=0.05,
                             command=self._load,
                             extraArgs=[saved_story])
            labels.append(l)
        self.load_list = DirectScrolledList(
            decButton_pos=(0.35, 0, 0.53),
            decButton_text="/\\",
            decButton_text_scale=0.04,
            decButton_borderWidth=(0.005, 0.005),
            incButton_pos=(0.35, 0, -0.02),
            incButton_text="\\/",
            incButton_text_scale=0.04,
            incButton_borderWidth=(0.005, 0.005),

            #frameSize = (0.0, 0.7, -0.05, 0.59),
            #frameColor = (1,0,0,0.5),
            pos=self.load_button.getPos(aspect2d),
            items=labels,
            numItemsVisible=4,
            forceHeight=0.11,
            itemFrame_frameSize=(-0.3, 0.3, -0.37, 0.11),
            itemFrame_pos=(0.35, 0, 0.4),
        )

    def export(self):
        """Export the current story to a text file."""
        memento = self.create_memento()
        try:
            f = open("story.txt", "w")
            try:
                f.write(memento.__str__())
            finally:
                f.close()
        except IOError:
            print 'IOError while exporting story!'
Ejemplo n.º 7
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)