Exemple #1
0
class Layout(object):
    def __init__(self, width, height, parent=None, frameColor=(1, 1, 1, 1), frameSize=(0, 0.5, -0.5, 0)):
        self.width = width
        self.height = height
        if parent is None:
            parent = aspect2d
        self.parent = parent
        self.frame = DirectFrame(parent=parent, frameColor=frameColor, frameSize=frameSize, state=DGG.DISABLED)
        self.frame.setPos(0, 0, 0)
        self.children = [[None for y in range(self.height)] for x in range(self.width)]
        self.children_width = [[0.0 for y in range(self.height)] for x in range(self.width)]
        self.children_height = [[0.0 for y in range(self.height)] for x in range(self.width)]

    def set_child(self, x, y, child):
        if x >= self.width or y >= self.height: return
        child.reparent_to(self.frame)
        self.children[x][y] = child
        bounds = child.getBounds()
        if bounds is not None:
            width = bounds[1] - bounds[0]
            height = bounds[3] - bounds[2]
            self.children_width[x][y] = width
            self.children_height[x][y] = height
        else:
            self.children_width[x][y] = 0
            self.children_height[x][y] = 0

    def recalc_positions(self):
        max_widths = []
        for x in range(self.width):
            max_width = 0.0
            for y in range(self.height):
                max_width = max(max_width, self.children_width[x][y])
            max_widths.append(max_width)
        max_heights = []
        for y in range(self.height):
            max_height = 0.0
            for x in range(self.width):
                max_height = max(max_height, self.children_height[x][y])
            max_heights.append(max_height)
        pos_x = 0.0
        for x in range(self.width):
            pos_y = 0.0
            for y in range(self.height):
                pos_y -= max_heights[y]
                child = self.children[x][y]
                if child is not None:
                    child.setPos(pos_x, 0, pos_y)
            pos_x += max_widths[x]
        self.frame['frameSize']= [0, pos_x, 0, pos_y]

    def destroy(self):
        self.frame.destroy()

    def reparent_to(self, parent):
        self.frame.reparent_to(parent)
class Window():
    __base: Final[ShowBase]
    __name: Final[str]
    __mouse1_press_callbacks: Final[List[Callable[[], None]]]

    __frame: Final[DirectFrame]
    __mouse_node: Final[NodePath]

    __zoom: float
    __visible: bool

    def __init__(self, base: ShowBase, name: str,
                 mouse1_press_callbacks: List[Callable[[], None]], *args,
                 **kwargs):
        self.__base = base
        self.__name = name
        self.__mouse1_press_callbacks = mouse1_press_callbacks

        self.__visible = True
        self.__zoom = 1 / 5

        if 'frameSize' not in kwargs:
            kwargs['frameSize'] = (-.8, .8, -1., 1.)

        self.__frame = DirectFrame(*args,
                                   parent=self.__base.aspect2d,
                                   **kwargs)
        self.__frame['state'] = DGG.NORMAL
        self.__frame.bind(DGG.B1PRESS, self.__start_drag)
        self.__frame.bind(DGG.B1RELEASE, self.__stop_drag)
        self.__frame.set_scale(self.zoom)

        # set sort value to ensure when window is reparented to mouse node it is on top
        # of everything else.
        self.__mouse_node = self.__base.aspect2d.attach_new_node(
            name + '_mouse_node', sort=100000000)
        self.__base.taskMgr.add(self.__mouse_node_task,
                                name + '_mouse_node_task')

    def __mouse_node_task(self, task):
        if self.__base.mouseWatcherNode.hasMouse():
            x = self.__base.mouseWatcherNode.getMouseX()
            y = self.__base.mouseWatcherNode.getMouseY()
            self.__mouse_node.setPos(self.__base.render2d, x, 0, y)
        return task.cont

    def __start_drag(self, *discarded):
        for c in self.__mouse1_press_callbacks:
            c()
        self.__frame.wrt_reparent_to(self.__mouse_node)

    def __stop_drag(self, *discarded):
        if self.__frame.get_parent() != self.__base.aspect2d:
            self.__frame.wrt_reparent_to(self.__base.aspect2d)

    @property
    def frame(self) -> DirectFrame:
        return self.__frame

    def focus(self) -> None:
        self.__frame.detach_node()
        self.__frame.reparent_to(self.__base.aspect2d)

    def zoom_in(self):
        self.__zoom += 0.05
        self.frame.set_scale(self.__zoom)

    def zoom_out(self):
        self.__zoom -= 0.05
        self.frame.set_scale(self.__zoom)

    @property
    def zoom(self) -> float:
        return self.__zoom

    def toggle_visible(self):
        if self.__visible:
            self.frame.hide()
        else:
            self.frame.show()
            self.focus()
        self.__visible = not self.__visible

    @property
    def visible(self) -> bool:
        return self.__visible