Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

I haven't tested this uber thoroughly, so adapt if needed; here's my adjustment to the code in the GitHub:

init python:
    class MouseTooltip(Tooltip, renpy.Displayable):
        """A Tooltip whose x/y position follows the mouse's."""
        action = Action

        def __init__(self, default, padding=None, virtual_cursor=None, *args, **kwargs):
            super(renpy.Displayable, self).__init__(*args, **kwargs)

            self.default = default
            self.value = default

            self.padding = padding or {}
            self.pad_x = self.padding.get('x', 0)
            self.pad_y = self.padding.get('y', 0)

            self.x = 0
            self.y = 0

            self.virtual_cursor = virtual_cursor

        def render(self, width, height, st, at):
            # Only Text() displayables have a size method
            try:
                w, h = self.value.size()

            except AttributeError:
                child_render = renpy.render(self.value, width, height, st, at)
                w, h = child_render.get_size()

            render = renpy.Render(w, h)
            render.place(self.value, x=self.x + self.pad_x, y=self.y + self.pad_y)
            return render

        def event(self, ev, x, y, st):
            if self.virtual_cursor and not pad_config.is_using_mouse():
                d = renpy.get_widget(None, self.virtual_cursor)
                if d is None:
                    raise Exception("There is no displayable with the id {}.".format(self.virtual_cursor))
                x, y = d.get_cursor_coords()
            if x != self.x:
                renpy.redraw(self, 0)
            if y != self.y:
                renpy.redraw(self, 0)
            self.x = x
            self.y = y
            # Pass the event to our child
            return self.value.event(ev, x, y, st)


image test_cursor_image = Text("↖", prefer_emoji=False,
    font="DejaVuSans.ttf", size=90, color="#FFF",
        outlines=[(2, "#000")])
default mtt = MouseTooltip(Text("No button selected."), padding={"x": 10, "y": -10}, virtual_cursor="vc_test")

screen test_tooltips():
    add mtt

    virtual_cursor:
        id 'vc_test'
        cursor ("test_cursor_image", 12, 30)
        vbox:
            align (0.5, 0.5) spacing 20
            textbutton "One.":
                action Notify("1")
                hovered mtt.Action(Text("The loneliest number."))

            textbutton "Two.":
                action Notify("2")
                hovered mtt.Action(Text("Is what it takes."))

            textbutton "Three.":
                action Notify("3")
                hovered mtt.Action(Text("A crowd."))

            textbutton "Hearts.":
                action Notify("3")
                hovered mtt.Action(Image("icons8-heart-outline-48.png"))

The main thing is you will need to provide your virtual cursor with an ID, and then pass that ID to your MouseTooltip (mine's "vc_test"). Also I cleaned up whatever was going on with that code's redrawing functions, as they were not working properly.

Thanks for taking the time to adapt the MouseTooltip code! I tried your test screen and it indeed works.

I tried adding the cursor to my hidden object screen, but I ran into the renpy.restart_interaction() error again. The biggest difference with your test screen was that my buttons are 1920x1080 px imagebuttons with focus_mask applied:

screen test_tooltips():
    tag menu

    add mtt
    virtual_cursor:
        id 'vc_test'
        cursor ("test_cursor_image", 12, 30)

        imagebutton:
            idle "/images/apple.png"
            focus_mask True
            hovered mtt.Action(Text(_("Apple"), style="mystyle"))
            action Call("apple_check")
        imagebutton:
            idle "/images/orange.png"
            focus_mask True
            hovered mtt.Action(Text(_("Orange"), style="mystyle"))
            action Call("orange_check")
        imagebutton:
            idle "/images/strawberry.png"
            focus_mask True
            hovered mtt.Action(Text(_("Orange"), style="mystyle"))
            action Call("strawberry_check")

Things I noticed:

  • if I press the Right direction key even very briefly, the cursor moves at ~200px to the right rather than a small movement
  • let's say apple.png contains a 300px wide image of an apple on a 1920x1080 px transparent background. The cursor starts on the left of the apple's pixels. If I hit the Right-direction key to get the cursor inside the apple, the cursor will instead keep moving right until all focus_mask pixels have been crossed and the cursors stops on the right outside the apple's pixels. It's like the cursor avoids the focus_mask.
  • the error typically happens when an item is at the edge of the screen and the cursor then tries moving beyond the 1920x1080 boundaries

I hope it makes sense. I could draw you an image if my explanation is not clear. Unfortunately; I can't go without imagebuttons in the project I'm doing.