All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.kotcrab.vis.ui.widget.Tooltip Maven / Gradle / Ivy

There is a newer version: 1.5.3
Show newest version
/*
 * Copyright 2014-2017 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.kotcrab.vis.ui.widget;

import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.EventListener;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Cell;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.Timer.Task;
import com.kotcrab.vis.ui.VisUI;
import com.kotcrab.vis.ui.util.ActorUtils;

/**
 * Tooltips are widgets that appear below other widget on mouse pointer hover. Each actor can have only one tooltip.
 * 

* LibGDX 1.6.4 introduced it's own systems of tooltips. VisUI tooltips existed before that and are unrelated and * incompatible with libGDX tooltips. VisUI tooltips will remain supported. * @author Kotcrab * @since 0.5.0 */ public class Tooltip extends VisTable { public static float DEFAULT_FADE_TIME = 0.3f; public static float DEFAULT_APPEAR_DELAY_TIME = 0.6f; /** * Controls whether to fade out tooltip when mouse was moved. Changing this will not affect already existing tooltips. * @see #setMouseMoveFadeOut(boolean) */ public static boolean MOUSE_MOVED_FADEOUT = false; private Actor target; private Actor content; private Cell contentCell; private boolean mouseMoveFadeOut = MOUSE_MOVED_FADEOUT; private TooltipInputListener listener; private DisplayTask displayTask; private float fadeTime = DEFAULT_FADE_TIME; private float appearDelayTime = DEFAULT_APPEAR_DELAY_TIME; private Tooltip (Builder builder) { super(true); TooltipStyle style = builder.style; if (style == null) style = VisUI.getSkin().get("default", TooltipStyle.class); init(style, builder.target, builder.content); if (builder.width != -1) { contentCell.width(builder.width); pack(); } } public Tooltip () { this("default"); } public Tooltip (String styleName) { super(true); init(VisUI.getSkin().get(styleName, TooltipStyle.class), null, null); } public Tooltip (TooltipStyle style) { super(true); init(style, null, null); } /** * Remove any attached tooltip from target actor * @param target that tooltips will be removed */ public static void removeTooltip (Actor target) { Array listeners = target.getListeners(); for (EventListener listener : listeners) { if (listener instanceof TooltipInputListener) target.removeListener(listener); } } private void init (TooltipStyle style, Actor target, Actor content) { this.target = target; this.content = content; this.listener = new TooltipInputListener(); this.displayTask = new DisplayTask(); setBackground(style.background); contentCell = add(content).padLeft(3).padRight(3).padBottom(2); pack(); if (target != null) attach(); addListener(new InputListener() { @Override public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { toFront(); return true; } @Override public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) { if (pointer == -1) { clearActions(); addAction(Actions.sequence(Actions.fadeIn(fadeTime, Interpolation.fade))); } } @Override public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) { if (pointer == -1) { fadeOut(); } } }); } /** * Attaches tooltip to current target, must be called if tooltip listener was removed from target (for example by * calling target.clearListeners() ) */ public void attach () { if (target == null) return; Array listeners = target.getListeners(); for (EventListener listener : listeners) { if (listener instanceof TooltipInputListener) { throw new IllegalStateException("More than one tooltip cannot be added to the same target!"); } } target.addListener(listener); } /** * Detaches tooltip form current target, does not change tooltip target meaning that this tooltip can be reattached to * same target by calling {@link Tooltip#attach()} */ public void detach () { if (target == null) return; target.removeListener(listener); } /** Sets new target for this tooltip, tooltip will be automatically detached from old target. */ public void setTarget (Actor newTarget) { detach(); target = newTarget; attach(); } public Actor getTarget () { return target; } private void fadeOut () { clearActions(); addAction(Actions.sequence(Actions.fadeOut(fadeTime, Interpolation.fade), Actions.removeActor())); } private VisTable fadeIn () { clearActions(); setColor(1, 1, 1, 0); addAction(Actions.sequence(Actions.fadeIn(fadeTime, Interpolation.fade))); return this; } public Actor getContent () { return content; } public void setContent (Actor content) { this.content = content; contentCell.setActor(content); pack(); } public Cell getContentCell () { return contentCell; } /** * Changes text tooltip to specified text. If tooltip content is not instance of VisLabel then previous tooltip content * will be replaced by VisLabel instance. * @param text next tooltip text */ public void setText (String text) { if (content instanceof VisLabel) { ((VisLabel) content).setText(text); } else { setContent(new VisLabel(text)); } pack(); } @Override public void setPosition (float x, float y) { super.setPosition((int) x, (int) y); } public float getAppearDelayTime () { return appearDelayTime; } public void setAppearDelayTime (float appearDelayTime) { this.appearDelayTime = appearDelayTime; } public float getFadeTime () { return fadeTime; } public void setFadeTime (float fadeTime) { this.fadeTime = fadeTime; } public boolean isMouseMoveFadeOut () { return mouseMoveFadeOut; } /** * @param mouseMoveFadeOut if true tooltip fill fade out when mouse was moved. If false tooltip will only fadeout on * mouse click or when mouse has exited target widget. Default is {@link Tooltip#MOUSE_MOVED_FADEOUT}. */ public void setMouseMoveFadeOut (boolean mouseMoveFadeOut) { this.mouseMoveFadeOut = mouseMoveFadeOut; } private class DisplayTask extends Task { @Override public void run () { if (target.getStage() == null) return; target.getStage().addActor(fadeIn()); ActorUtils.keepWithinStage(getStage(), Tooltip.this); } } private class TooltipInputListener extends InputListener { @Override public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { displayTask.cancel(); Tooltip.this.toFront(); fadeOut(); return true; } @Override public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) { if (pointer == -1) { Vector2 targetPos = target.localToStageCoordinates(new Vector2()); setX(targetPos.x + (target.getWidth() - getWidth()) / 2); float tooltipY = targetPos.y - getHeight() - 6; float stageHeight = target.getStage().getHeight(); //is there enough space to display above widget? if (stageHeight - tooltipY > stageHeight) setY(targetPos.y + target.getHeight() + 6); //display above widget else setY(tooltipY); //display below displayTask.cancel(); Timer.schedule(displayTask, appearDelayTime); } } @Override public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) { if (pointer == -1) { displayTask.cancel(); fadeOut(); } } @Override public boolean mouseMoved (InputEvent event, float x, float y) { if (mouseMoveFadeOut && isVisible() && getActions().size == 0) fadeOut(); return false; } } public static class TooltipStyle { public Drawable background; public TooltipStyle () { } public TooltipStyle (TooltipStyle style) { this.background = style.background; } public TooltipStyle (Drawable background) { this.background = background; } } public static class Builder { private final Actor content; private Actor target = null; private TooltipStyle style = null; private float width = -1; public Builder (Actor content) { this.content = content; } public Builder (String text) { this(text, Align.center); } public Builder (String text, int textAlign) { VisLabel label = new VisLabel(text); label.setAlignment(textAlign); this.content = label; } public Builder target (Actor target) { this.target = target; return this; } public Builder style (String styleName) { return style(VisUI.getSkin().get(styleName, TooltipStyle.class)); } public Builder style (TooltipStyle style) { this.style = style; return this; } /** Sets tooltip width. If tooltip content is text only then calling this will automatically enable label wrapping. */ public Builder width (float width) { if (width < 0) throw new IllegalArgumentException("width must be > 0"); this.width = width; if (content instanceof VisLabel) { ((VisLabel) content).setWrap(true); } return this; } public Tooltip build () { return new Tooltip(this); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy