Exemplo n.º 1
0
class CharacterGUI:
    """Widget with the selected character info."""

    def __init__(self):
        self.char = None  # the chosen character
        self.rest_list_shown = False
        self._status_lab = None
        self._rest_buttons = {}
        self._char_desc_wids = []
        self._char_desc_shown = False

        self._fr = DirectFrame(
            parent=base.a2dTopLeft,  # noqa: F821
            frameSize=(-0.31, 0.31, -0.1, 0.115),
            pos=(0.31, 0, -1.9),
            frameTexture=GUI_PIC + "metal1.png",
            state=DGG.NORMAL,
        )
        self._fr.setTransparency(TransparencyAttrib.MAlpha)

        # a "?" button to open a detailed description of the character
        self._char_desc_but = DirectButton(
            parent=self._fr,
            pos=(0.27, 0, 0.0675),
            command=self._show_char_desc,
            clickSound=base.main_menu.click_snd,  # noqa: F821
            **ABOUT_BUT_PARAMS,
        )
        DirectLabel(  # Name:
            parent=self._fr,
            text=base.labels.CHARACTERS[0],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(-0.22, 0, 0.07),
        )
        self._char_name = DirectLabel(
            parent=self._fr,
            text="",
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=SILVER_COL,
            pos=(-0.09, 0, 0.069),
        )
        self._traits = DirectLabel(
            parent=self._fr,
            text="",
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=(0.028, 0.028),
            text_fg=SILVER_COL,
            text_font=base.main_font,  # noqa: F821
            pos=(0, 0, 0.025),
        )
        DirectLabel(  # Class:
            parent=self._fr,
            text=base.labels.CHARACTERS[1],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(0.05, 0, 0.07),
        )
        self._char_class = DirectLabel(
            parent=self._fr,
            text="",
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=SILVER_COL,
            pos=(0.17, 0, 0.068),
        )
        DirectLabel(  # Health
            parent=self._fr,
            text=base.labels.CHARACTERS[2],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(-0.22, 0, -0.015),
        )
        self._char_health = DirectWaitBar(
            parent=self._fr,
            frameSize=(-0.17, 0.17, -0.002, 0.002),
            frameColor=(0.35, 0.35, 0.35, 1),
            value=0,
            barColor=(0.85, 0.2, 0.28, 1),
            pos=(0.07, 0, -0.008),
        )
        DirectLabel(  # Energy
            parent=self._fr,
            text=base.labels.CHARACTERS[3],  # noqa: F821
            text_font=base.main_font,  # noqa: F821
            frameSize=(0.1, 0.1, 0.1, 0.1),
            text_scale=0.03,
            text_fg=RUST_COL,
            pos=(-0.216, 0, -0.06),
        )
        self._char_energy = DirectWaitBar(
            parent=self._fr,
            frameSize=(-0.17, 0.17, -0.002, 0.002),
            frameColor=(0.35, 0.35, 0.35, 1),
            value=0,
            barColor=(0.46, 0.61, 0.53, 1),
            pos=(0.07, 0, -0.053),
        )
        self._tip = OnscreenText(
            parent=base.render2d,  # noqa: F821
            text="",
            font=base.main_font,  # noqa: F821
            scale=(0.021, 0.027),
            fg=SILVER_COL,
            bg=(0, 0, 0, 0.4),
        )
        self._tip.hide()

        self._disease = DirectFrame(
            parent=self._fr,
            frameSize=(-0.02, 0.02, -0.02, 0.02),
            pos=(0.27, 0, -0.008),
            frameTexture=GUI_PIC + "disease.png",
        )
        self._disease.setTransparency(TransparencyAttrib.MAlpha)

        self.clear_char_info()

    def _update_char_info(self, task):
        """Track the chosen character parameters in the GUI."""
        if self.char.is_dead:
            self.clear_char_info()
            return task.done

        self._char_health["value"] = self.char.health
        self._char_energy["value"] = self.char.energy
        self._traits["text"] = ", ".join(self.char.traits)

        if self.char.is_diseased:
            self._disease.show()
        else:
            self._disease.hide()

        if self._char_desc_shown:
            self._update_desc()

        return task.again

    def _update_desc(self):
        """Update the chosen character description."""
        to_del = []
        for wid in self._char_desc_wids:
            if wid["text"] not in (
                # Traits
                base.labels.CHARACTERS[5],  # noqa: F821
                # Status
                base.labels.CHARACTERS[4],  # noqa: F821
                "",
            ):
                wid.destroy()
                to_del.append(wid)

        for del_wid in to_del:
            self._char_desc_wids.remove(del_wid)

        self._fill_status(self._fill_traits(0.64))

    def _fill_traits(self, shift):
        """Fill the chosen character traits.

        Args:
            shift (float): Z-coor for the new widgets.

        Returns:
            float: Z-coor including the new widgets shift.
        """
        shift -= 0.03
        for trait in self.char.traits + self.char.disabled_traits:
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    text=trait,
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.03,
                    text_font=base.main_font,  # noqa: F821
                    text_fg=SILVER_COL
                    if trait in self.char.traits
                    else (0.3, 0.3, 0.3, 1),
                    pos=(0, 0, shift),
                )
            )
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    text=base.labels.TRAIT_DESC[trait],  # noqa: F821
                    text_font=base.main_font,  # noqa: F821
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.029,
                    text_fg=SILVER_COL
                    if trait in self.char.traits
                    else (0.3, 0.3, 0.3, 1),
                    pos=(0, 0, shift - 0.045),
                )
            )
            shift -= 0.1
        return shift

    def _fill_status(self, shift):
        """Fill the chosen character status.

        Args:
            shift (float): Z-coor for the new widgets.
        """
        shift -= 0.04
        for status in self.char.statuses:
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    text=status,
                    text_font=base.main_font,  # noqa: F821
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.029,
                    text_fg=SILVER_COL,
                    pos=(0, 0, shift),
                )
            )
            shift -= 0.045

    def _show_char_desc(self):
        """Show detailed character description.

        Includes description of every character's
        trait and their current status.
        """
        if self._char_desc_shown:
            self._fr["frameSize"] = (-0.31, 0.31, -0.1, 0.115)
            clear_wids(self._char_desc_wids)
            self._status_lab = None
        else:
            shift = 0.7
            self._fr["frameSize"] = (-0.31, 0.31, -0.1, shift)
            shift -= 0.06
            self._char_desc_wids.append(
                DirectLabel(
                    parent=self._fr,
                    # Traits
                    text=base.labels.CHARACTERS[5],  # noqa: F821,
                    text_font=base.main_font,  # noqa: F821,
                    frameSize=(0.1, 0.1, 0.1, 0.1),
                    text_scale=0.03,
                    text_fg=RUST_COL,
                    pos=(-0.225, 0, shift),
                )
            )
            if self.char.id in base.team.chars.keys():  # noqa: F821
                traits_but = DirectButton(
                    parent=self._fr,
                    text="",
                    frameSize=(-0.025, 0.025, -0.025, 0.025),
                    frameTexture=GUI_PIC + "like.png",
                    relief="flat",
                    pos=(0.265, 0, shift + 0.013),
                    command=base.traits_gui.show,  # noqa: F821
                )
                traits_but.bind(
                    DGG.ENTER, self._highlight_traits_but, extraArgs=[traits_but]
                )
                traits_but.bind(
                    DGG.EXIT, self._dehighlight_traits_but, extraArgs=[traits_but]
                )

                self._char_desc_wids.append(traits_but)

            shift = self._fill_traits(shift)

            self._status_lab = DirectLabel(  # Status
                parent=self._fr,
                # Status
                text=base.labels.CHARACTERS[4],  # noqa: F821
                text_font=base.main_font,  # noqa: F821
                frameSize=(0.1, 0.1, 0.1, 0.1),
                text_scale=0.03,
                text_fg=RUST_COL,
                pos=(-0.221, 0, shift),
            )
            self._char_desc_wids.append(self._status_lab)
            self._fill_status(shift)

        self._char_desc_shown = not self._char_desc_shown

    def _dehighlight_traits_but(self, button, _):
        """Dehighlight traits tweaking button.

        Args:
            button (panda3d.gui.DirectGui.DirectButton):
                Button to dehighlight.
        """
        button["frameTexture"] = GUI_PIC + "like.png"

    def _highlight_traits_but(self, button, _):
        """Hightlight traits tweaking button.

        Args:
            button (panda3d.gui.DirectGui.DirectButton):
                Button to highlight.
        """
        button["frameTexture"] = GUI_PIC + "hover_like.png"

    def clear_char_info(self, clear_resting=True):
        """Clear the character GUI.

        Args:
            clear_resting (bool):
                Optional. A flag indicating if the list of the
                resting characters should also be closed.
        """
        for wid in (
            self._char_name,
            self._char_class,
            self._char_health,
            self._char_energy,
            self._traits,
            self._char_desc_but,
            self._disease,
        ):
            wid.hide()

        if self._char_desc_shown:
            self._show_char_desc()

        taskMgr.remove("track_char_info")  # noqa: F821
        self.char = None

        if clear_resting:
            for but in self._rest_buttons.values():
                but.destroy()

        self.rest_list_shown = False

    def destroy_char_button(self, char_id):
        """Hide the given character button from the resting characters list.

        Args:
            char_id (str): Character id.
        """
        if char_id in self._rest_buttons.keys():
            self._rest_buttons[char_id].destroy()
            self._rest_buttons.pop(char_id)

    def hide_tip(self):
        """Hide the tooltip."""
        self._tip.hide()

    def show_char_info(self, char):
        """Show the given character status.

        Args:
            char (units.crew.character.Character):
                The chosen character object.
        """
        self._char_name["text"] = char.name
        self._char_class["text"] = char.class_.capitalize()
        self._traits["text"] = ", ".join(char.traits)

        self._char_health["range"] = char.class_data["health"]
        self._char_health["value"] = char.health
        self._char_energy["value"] = char.energy

        if char.is_diseased:
            self._disease.show()
        else:
            self._disease.hide()

        self.char = char
        self._char_name.show()
        self._char_class.show()
        self._char_health.show()
        self._char_energy.show()
        self._traits.show()
        self._char_desc_but.show()

        if self._char_desc_shown:
            self._show_char_desc()
            self._show_char_desc()

        taskMgr.doMethodLater(  # noqa: F821
            0.5, self._update_char_info, "track_char_info"
        )

    def show_tooltip(self, text):
        """Show tooltip with the given text.

        Args:
            text (str): Text to show in the tooltip.
        """
        if not base.mouseWatcherNode.hasMouse():  # noqa: F821
            return

        if self.rest_list_shown and text == "Rest zone":
            return

        self._tip.setText(text)
        self._tip.setX(base.mouseWatcherNode.getMouseX())  # noqa: F821
        self._tip.setY(base.mouseWatcherNode.getMouseY())  # noqa: F821
        self._tip.show()

    def show_resting_chars(self, part):
        """Show a list of the characters resting in this part.

        Args:
            part (Train.RestPart): Rest part of the Train.
        """
        if self.rest_list_shown:
            return

        self._tip.hide()
        self.rest_list_shown = True

        x = base.mouseWatcherNode.getMouseX()  # noqa: F821
        z = base.mouseWatcherNode.getMouseY()  # noqa: F821

        self._rest_buttons["title"] = DirectButton(
            pos=(x, 0, z),
            text=base.labels.TIPS[0],  # noqa: F821
            text_fg=RUST_COL,
            text_font=base.main_font,  # noqa: F821
            frameColor=(0, 0, 0, 0.6),
            scale=(0.04, 0, 0.03),
        )
        shift = -0.039
        for char in part.chars:
            if char.is_dead:
                continue

            self._rest_buttons[char.id] = DirectButton(
                pos=(x, 0, z + shift),
                text=char.name,
                text_fg=SILVER_COL,
                frameColor=(0, 0, 0, 0.6),
                command=base.common_ctrl.choose_char,  # noqa: F821
                extraArgs=[char.id],
                scale=(0.04, 0, 0.03),
            )
            shift -= 0.033

    def move_status_label(self, place):
        """Move the status label widget.

        Args:
            place (int): Place to shift the widget.
        """
        if self._status_lab is not None:
            self._status_lab.setZ(self._status_lab.getZ() + place / 10)

    def update_resting_chars(self, part):
        """Update the list of the resting characters.

        Args:
            part (train.part.TrainPart): Rest train part.
        """
        for key, but in self._rest_buttons.items():
            if key != "title":
                but.destroy()
                self._rest_buttons[key] = None

        x, _, z = self._rest_buttons["title"].getPos()

        shift = -0.039
        for char in part.chars:
            self._rest_buttons[char.id] = DirectButton(
                pos=(x, 0, z + shift),
                text=char.name,
                text_fg=SILVER_COL,
                frameColor=(0, 0, 0, 0.6),
                command=base.common_ctrl.choose_char,  # noqa: F821
                extraArgs=[char.id],
                scale=(0.04, 0, 0.03),
            )
            shift -= 0.033
Exemplo n.º 2
0
class DirectTooltip():
    def __init__(self):

        self.tooltipText = DirectLabel(
            text = "Tooltip",
            text_fg = (1,1,1,1),
            text_scale = 0.05,
            text_align = TextNode.ALeft,
            frameColor = (0, 0, 0, 0.75),
            borderWidth = (0.1, 0.1))
        self.tooltipText.setTransparency(True)

        self.textXShift = 0.05
        self.textYShift = -0.08

        self.mousePos = None

        # this will determine when the tooltip should be moved in the
        # respective direction, whereby
        # 1  : display edge
        # <1 : margin inside the window
        # >1 : margin outside the window
        self.xEdgeStartShift = 0.99
        self.yEdgeStartShift = 0.99

        self.tooltipText.hide()

    def show(self, text=None, args=None):
        if text is not None:
            self.tooltipText.setText(text)
            self.tooltipText.resetFrameSize()
        self.tooltipText.show()

        # add the tooltips update task so it will be updated every frame
        base.taskMgr.add(self.updateTooltipPos, "task_updateTooltipPos")

    def delete(self, args=None):
        self.tooltipText.removeNode()

        # remove the tooltips update task
        base.taskMgr.remove("task_updateTooltipPos")

    def updateTooltipPos(self, task):
        # calculate new aspec tratio
        wp = base.win.getProperties()
        aspX = 1.0
        aspY = 1.0
        wpXSize = wp.getXSize()
        wpYSize = wp.getYSize()
        if wpXSize > wpYSize:
            aspX = wpXSize / float(wpYSize)
        else:
            aspY = wpYSize / float(wpXSize)

        # variables to store the mouses current x and y position
        x = 0.0
        y = 0.0
        if base.mouseWatcherNode.hasMouse():
            self.tooltipText.show()
            # get the mouse position
            x = base.mouseWatcherNode.getMouseX()
            y = base.mouseWatcherNode.getMouseY()

            # Move the tooltip to the mouse

            # set the text to the current mouse position
            self.tooltipText.setPos(
                (x*aspX) + self.textXShift,
                0,
                (y*aspY)+self.textYShift)

            bounds = self.tooltipText.getBounds()
            # bounds = left, right, bottom, top

            # calculate the texts bounds respecting its current position
            xLeft = self.tooltipText.getX() + bounds[0]*self.tooltipText.getScale()[0]
            xRight = self.tooltipText.getX() + bounds[1]*self.tooltipText.getScale()[0]
            yUp = self.tooltipText.getZ() + bounds[3]*self.tooltipText.getScale()[1]
            yDown = self.tooltipText.getZ() + bounds[2]*self.tooltipText.getScale()[1]

            # these will be used to shift the text in the desired direction
            xShift = 0.0
            yShift = 0.0
            if xRight/aspX > self.xEdgeStartShift:
                # shift to the left
                xShift = self.xEdgeStartShift - xRight/aspX
            elif xLeft/aspX < -self.xEdgeStartShift:
                # shift to the right
                xShift = -(self.xEdgeStartShift + xLeft/aspX)
            if yUp/aspY > self.yEdgeStartShift:
                # shift down
                yShift = self.yEdgeStartShift - yUp/aspY
            elif yDown/aspY < -self.yEdgeStartShift:
                # shift up
                yShift = -(self.yEdgeStartShift + yDown/aspY)

            # some aspect ratio calculation
            xShift *= aspX
            yShift *= aspY

            # move the tooltip to the new position
            self.tooltipText.setX(self.tooltipText.getX() + xShift)
            self.tooltipText.setZ(self.tooltipText.getZ() + yShift)
        else:
            self.tooltipText.delete()


        # continue the task until it got manually stopped
        return task.cont