Drag and Drop Inventory with LibGDX (Part IV)

In this last part of our series on an inventory we are going to add the finishing touch, namely tooltips.

The SlotTooltip

The SlotTooltip is a Window itself. In contrast to the inventory, it does not have a button to close. Furthermore it displays the amount of items and the item name in the title bar. The content area could display anything, but to keep it simple, it will be just another dummy Label with some text. It’s also a SlotListener and will get notified when a slot changes. According to the new state of the slot, the tooltip will hide itself when the slot is empty.

public class SlotTooltip extends Window implements SlotListener {

    private Skin skin;

    private Slot slot;

    public SlotTooltip(Slot slot, Skin skin) {
        super("Tooltip...", skin);
        this.slot = slot;
        this.skin = skin;
        hasChanged(slot);
        slot.addListener(this);
        setVisible(false);
    }

    @Override
    public void hasChanged(Slot slot) {
        if (slot.isEmpty()) {
            setVisible(false);
            return;
        }

        // title displays the amount
        setTitle(slot.getAmount() + "x " + slot.getItem());
        clear();
        Label label = new Label("Super awesome description of " + slot.getItem(), skin);
        add(label);
        pack();
    }

    @Override
    public void setVisible(boolean visible) {
        super.setVisible(visible);
        // the listener sets this to true in case the slot is hovered
        // however, we don't want that in case the slot is empty
        if (slot.isEmpty()) {
            super.setVisible(false);
        }
    }

}

Making the tooltip follow the cursor

The following listener will be attached to every SlotActor and will activate or disable the tooltip when the mouse hovers over a certain slot. It will also hide the tooltip when the mouse is not hovering anymore. Furthermore it adjusts the tooltip’s position based on the movement of the mouse cursor.

public class TooltipListener extends InputListener {

    private boolean inside;

    private Actor tooltip;
    private boolean followCursor;

    private Vector2 position = new Vector2();
    private Vector2 tmp = new Vector2();
    private Vector2 offset = new Vector2(10, 10);

    public TooltipListener(Actor tooltip, boolean followCursor) {
        this.tooltip = tooltip;
        this.followCursor = followCursor;
    }

    @Override
    public boolean mouseMoved(InputEvent event, float x, float y) {
        if (inside && followCursor) {
            event.getListenerActor().localToStageCoordinates(tmp.set(x, y));
            tooltip.setPosition(tmp.x + position.x + offset.x, tmp.y + position.y + offset.y);
        }
        return false;
    }

    @Override
    public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) {
        inside = true;
        tooltip.setVisible(true);
        tmp.set(x, y);
        event.getListenerActor().localToStageCoordinates(tmp);
        tooltip.setPosition(tmp.x + position.x + offset.x, tmp.y + position.y + offset.y);
        tooltip.toFront();
    }

    @Override
    public void exit(InputEvent event, float x, float y, int pointer, Actor toActor) {
        inside = false;
        tooltip.setVisible(false);
    }

    /**
     * The offset of the tooltip from the touch position. It should not be
     * positive as the tooltip will flicker otherwise.
     */
    public void setOffset(float offsetX, float offsetY) {
        offset.set(offsetX, offsetY);
    }

}

Usage

Attaching a tooltip to a slot is really easy now. All it takes is adding a new SlotTooltip to the stage and registering the TooltipListener.

public SlotActor(Skin skin, Slot slot) {
    ....
    SlotTooltip tooltip = new SlotTooltip(slot, skin);
    InventoryScreen.stage.addActor(tooltip);
    addListener(new TooltipListener(tooltip, true));
}

The end

Finally, that’s it. We’ve created an interactive inventory with all sorts of features. For the full code see our public GitHub repository.

Leave a Reply

Your email address will not be published. Required fields are marked *