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

net.dermetfan.gdx.scenes.scene2d.ui.ContextMenu Maven / Gradle / Ivy

There is a newer version: 0.13.4
Show newest version
/** Copyright 2014 Robin Stumm ([email protected], http://dermetfan.net)
 *
 *  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 net.dermetfan.gdx.scenes.scene2d.ui;

import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Event;
import com.badlogic.gdx.scenes.scene2d.EventListener;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.utils.Array;
import net.dermetfan.gdx.Multiplexer;
import net.dermetfan.gdx.scenes.scene2d.Scene2DUtils;

/** A classic context menu. Add this to the actor that the user should be able to right-click.
 *  Note that this can only hide on events of other actors if it receives them, so consider adding all your context menus to a {@link Manager} high up in the hierarchy (e.g. added to the {@link com.badlogic.gdx.scenes.scene2d.Stage Stage}).
 *  @author dermetfan
 *  @since 0.4.0 */
public class ContextMenu extends PositionedPopup {

	/** Hides all its {@link #receivers context menus} when escape is pressed or something is touched (except a {@link ContextMenu#popup} or its children).
	 *  Meant to be added added far up in the hierarchy (e.g. the {@link com.badlogic.gdx.scenes.scene2d.Stage Stage} itself) so it can hide on events on possibly all actors.
	 *  @author dermetfan
	 *  @since 0.4.0 */
	public static class Manager extends Multiplexer implements EventListener {

		/** @see Multiplexer#Multiplexer(Object[]) */
		public Manager(ContextMenu... receivers) {
			super(receivers);
		}

		/** @see Multiplexer#Multiplexer(Array)  */
		public Manager(Array receivers) {
			super(receivers);
		}

		/** Hides {@link #receivers} on {@link Keys#ESCAPE} and {@link InputEvent.Type#touchDown} events on actors that are not their {@link ContextMenu#popup popups} or its children. */
		@Override
		public boolean handle(final Event event) {
			if(event instanceof InputEvent) {
				InputEvent ie = (InputEvent) event;
				switch(ie.getType()) {
				case keyDown:
					if(ie.getKeyCode() == Keys.ESCAPE) // escape hides all
						for(ContextMenu menu : receivers)
							menu.hide(event);
					break;
				case touchDown:
					if(ie.getButton() == Buttons.LEFT) { // ContextMenus probably hid itself, so show again if they had parents
						for(ContextMenu menu : receivers)
							if(event.getTarget().isDescendantOf(menu.getPopup())) { // target had parents
								for(EventListener listener : event.getTarget().getListeners()) // show menus again
									if(listener instanceof ContextMenu)
										((ContextMenu) listener).show(event);
							} else // target didn't have parents or a context menu, so hide
								menu.hide(event);
					} else {
						for(ContextMenu menu : receivers) // don't hide if popup or one of its parents was touched
							if(event.getTarget().getListeners().contains(menu, true) || menu.getPopup().isAscendantOf(event.getTarget()))
								return false;
						for(ContextMenu menu : receivers)
							menu.hide(event);
					}
				}
			}
			return false;
		}

	}

	/** Classic position of context menus on the right of the actor.
* Positions the left border of the {@link #popup} at the right border of the {@link Event#getTarget() target} and aligns their top borders. * @author dermetfan * @since 0.4.0 */ public class ContextMenuPosition implements Position { /** @return {@link Scene2DUtils#tmp} */ @Override public Vector2 apply(Event event) { Actor parentMenu = event.getTarget(); Vector2 pos = Scene2DUtils.positionInStageCoordinates(parentMenu); pos.x += parentMenu.getWidth(); pos.y -= getPopup().getHeight() - parentMenu.getHeight(); return pos; } } /** Positions the top border of the {@link #popup} at the bottom border of the {@link Event#getTarget() target}. * @author dermetfan * @since 0.4.0 */ public class BelowPosition implements Position { /** @return {@link Scene2DUtils#tmp} */ @Override public Vector2 apply(Event event) { return Scene2DUtils.positionInStageCoordinates(event.getTarget()).sub(0, getPopup().getHeight()); } } /** creates a new {@code ContextMenu} with {@link ContextMenuPosition} */ public ContextMenu(T popup) { super(popup, null); setPosition(new ContextMenuPosition()); } /** @see PositionedPopup#PositionedPopup(Actor, Position) */ public ContextMenu(T popup, Position position) { super(popup, position); } /** @param manager the {@link Manager} to add this ContextMenu to (may be null) */ public ContextMenu(T popup, Manager manager) { this(popup); if(manager != null) manager.add(this); } /** @param manager the {@link Manager} to add this {@code ContextMenu} to (may be null) */ public ContextMenu(T popup, Position position, Manager manager) { super(popup, position); if(manager != null) manager.add(this); } /** {@link #show(Event) Shows} on right click and menu key press. Hides on left click, escape key and back key. * Note that this will not hide on clicks on other actors except the {@link Event#getListenerActor()}'s children. */ @Override public boolean handle(Event e) { if(!(e instanceof InputEvent)) return false; InputEvent event = (InputEvent) e; switch(event.getType()) { case touchDown: return event.getButton() == Buttons.RIGHT ? show(event) : hide(event); // right shows, left hides case keyDown: if(event.getKeyCode() == Keys.MENU) // menu key shows return show(event); else if(event.getKeyCode() == Keys.ESCAPE || event.getKeyCode() == Keys.BACK) // escape and back hide return hide(event); } return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy