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

com.badlogic.gdx.scenes.scene2d.ui.SplitPane Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright 2011 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.badlogic.gdx.scenes.scene2d.ui;

import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Layout;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.utils.ScissorStack;
import com.badlogic.gdx.utils.GdxRuntimeException;

/** A container that divides two widgets either horizontally or vertically and allows the user to resize them. The child widgets
 * are always sized to fill the half of the splitpane.
 * 

* The preferred size of a splitpane is that of the child widgets and the size of the {@link SplitPaneStyle#handle}. The widgets * are sized depending on the splitpane's size and the {@link #setSplitAmount(float) split position}. * @author mzechner * @author Nathan Sweet */ public class SplitPane extends WidgetGroup { private SplitPaneStyle style; private Actor firstWidget, secondWidget; private boolean vertical; private float splitAmount = 0.5f, minAmount, maxAmount = 1; private float oldSplitAmount; private boolean touchDrag; private Rectangle firstWidgetBounds = new Rectangle(); private Rectangle secondWidgetBounds = new Rectangle(); private Rectangle handleBounds = new Rectangle(); private Rectangle firstScissors = new Rectangle(); private Rectangle secondScissors = new Rectangle(); private Vector2 lastPoint = new Vector2(); private Vector2 handlePosition = new Vector2(); /** Creates a horizontal splitpane with no children. */ public SplitPane (Skin skin) { this(null, null, false, skin); } /** @param firstWidget May be null. * @param secondWidget May be null. */ public SplitPane (Actor firstWidget, Actor secondWidget, boolean vertical, Skin skin) { this(firstWidget, secondWidget, vertical, skin.getStyle("default-horizontal", SplitPaneStyle.class), null); } /** @param firstWidget May be null. * @param secondWidget May be null. */ public SplitPane (Actor firstWidget, Actor secondWidget, boolean vertical, SplitPaneStyle style) { this(firstWidget, secondWidget, vertical, style, null); } /** @param firstWidget May be null. * @param secondWidget May be null. */ public SplitPane (Actor firstWidget, Actor secondWidget, boolean vertical, SplitPaneStyle style, String name) { super(name); this.firstWidget = firstWidget; this.secondWidget = secondWidget; this.vertical = vertical; setStyle(style); setFirstWidget(firstWidget); setSecondWidget(secondWidget); width = getPrefWidth(); height = getPrefHeight(); } public void setStyle (SplitPaneStyle style) { this.style = style; invalidateHierarchy(); } /** Returns the split pane's style. Modifying the returned style may not have an effect until {@link #setStyle(SplitPaneStyle)} * is called. */ public SplitPaneStyle getStyle () { return style; } @Override public void layout () { if (!vertical) calculateHorizBoundsAndPositions(); else calculateVertBoundsAndPositions(); if (firstWidget != null && firstWidget.width != firstWidgetBounds.width || firstWidget.height != firstWidgetBounds.height) { firstWidget.x = firstWidgetBounds.x; firstWidget.y = firstWidgetBounds.y; firstWidget.width = firstWidgetBounds.width; firstWidget.height = firstWidgetBounds.height; if (firstWidget instanceof Layout) { Layout layout = (Layout)firstWidget; layout.invalidate(); layout.validate(); } } if (secondWidget != null && secondWidget.width != secondWidgetBounds.width || secondWidget.height != secondWidgetBounds.height) { secondWidget.x = secondWidgetBounds.x; secondWidget.y = secondWidgetBounds.y; secondWidget.width = secondWidgetBounds.width; secondWidget.height = secondWidgetBounds.height; if (secondWidget instanceof Layout) { Layout layout = (Layout)secondWidget; layout.invalidate(); layout.validate(); } } } @Override public float getPrefWidth () { float width = firstWidget instanceof Layout ? ((Layout)firstWidget).getPrefWidth() : firstWidget.width; width += secondWidget instanceof Layout ? ((Layout)secondWidget).getPrefWidth() : secondWidget.width; if (!vertical) width += style.handle.getTotalWidth(); return width; } @Override public float getPrefHeight () { float height = firstWidget instanceof Layout ? ((Layout)firstWidget).getPrefHeight() : firstWidget.height; height += secondWidget instanceof Layout ? ((Layout)secondWidget).getPrefHeight() : secondWidget.height; if (vertical) height += style.handle.getTotalHeight(); return height; } public float getMinWidth () { return 0; } public float getMinHeight () { return 0; } public void setVertical (boolean vertical) { this.vertical = vertical; } private void calculateHorizBoundsAndPositions () { NinePatch handle = style.handle; float availWidth = width - handle.getTotalWidth(); float leftAreaWidth = (int)(availWidth * splitAmount); float rightAreaWidth = availWidth - leftAreaWidth; float handleWidth = handle.getTotalWidth(); firstWidgetBounds.set(0, 0, leftAreaWidth, height); secondWidgetBounds.set(leftAreaWidth + handleWidth, 0, rightAreaWidth, height); handleBounds.set(leftAreaWidth, 0, handleWidth, height); } private void calculateVertBoundsAndPositions () { NinePatch handle = style.handle; float availHeight = height - handle.getTotalHeight(); float topAreaHeight = (int)(availHeight * splitAmount); float bottomAreaHeight = availHeight - topAreaHeight; float handleHeight = handle.getTotalHeight(); firstWidgetBounds.set(0, height - topAreaHeight, width, topAreaHeight); secondWidgetBounds.set(0, 0, width, bottomAreaHeight); handleBounds.set(0, bottomAreaHeight, width, handleHeight); } @Override public void draw (SpriteBatch batch, float parentAlpha) { validate(); NinePatch handle = style.handle; applyTransform(batch); Matrix4 transform = batch.getTransformMatrix(); if (firstWidget != null) { ScissorStack.calculateScissors(stage.getCamera(), transform, firstWidgetBounds, firstScissors); if (ScissorStack.pushScissors(firstScissors)) { drawChild(firstWidget, batch, parentAlpha); ScissorStack.popScissors(); } } if (secondWidget != null) { ScissorStack.calculateScissors(stage.getCamera(), transform, secondWidgetBounds, secondScissors); if (ScissorStack.pushScissors(secondScissors)) { drawChild(secondWidget, batch, parentAlpha); ScissorStack.popScissors(); } } batch.setColor(color.r, color.g, color.b, color.a); handle.draw(batch, handleBounds.x, handleBounds.y, handleBounds.width, handleBounds.height); resetTransform(batch); } @Override public boolean touchDown (float x, float y, int pointer) { if (pointer != 0) return false; if (handleBounds.contains(x, y)) { touchDrag = true; lastPoint.set(x, y); handlePosition.set(handleBounds.x, handleBounds.y); return true; } return super.touchDown(x, y, pointer); } @Override public void touchUp (float x, float y, int pointer) { if (touchDrag) touchDrag = false; else super.touchUp(x, y, pointer); } @Override public void touchDragged (float x, float y, int pointer) { if (!touchDrag) { super.touchDragged(x, y, pointer); return; } NinePatch handle = style.handle; if (!vertical) { float delta = x - lastPoint.x; float availWidth = width - handle.getTotalWidth(); float dragX = handlePosition.x + delta; handlePosition.x = dragX; dragX = Math.max(0, dragX); dragX = Math.min(availWidth, dragX); splitAmount = dragX / availWidth; if (splitAmount < minAmount) splitAmount = minAmount; if (splitAmount > maxAmount) splitAmount = maxAmount; lastPoint.set(x, y); } else { float delta = y - lastPoint.y; float availHeight = height - handle.getTotalHeight(); float dragY = handlePosition.y + delta; handlePosition.y = dragY; dragY = Math.max(0, dragY); dragY = Math.min(availHeight, dragY); splitAmount = 1 - (dragY / availHeight); if (splitAmount < minAmount) splitAmount = minAmount; if (splitAmount > maxAmount) splitAmount = maxAmount; lastPoint.set(x, y); } invalidate(); } /** @param split The split amount between the min and max amount. */ public void setSplitAmount (float split) { this.splitAmount = Math.max(Math.min(maxAmount, split), minAmount); invalidate(); } public float getSplit () { return splitAmount; } public void setMinSplitAmount (float minAmount) { if (minAmount < 0) throw new GdxRuntimeException("minAmount has to be >= 0"); if (minAmount >= maxAmount) throw new GdxRuntimeException("minAmount has to be < maxAmount"); this.minAmount = minAmount; } public void setMaxSplitAmount (float maxAmount) { if (maxAmount > 1) throw new GdxRuntimeException("maxAmount has to be >= 0"); if (maxAmount <= minAmount) throw new GdxRuntimeException("maxAmount has to be > minAmount"); this.maxAmount = maxAmount; } /** @param widget May be null. */ public void setFirstWidget (Actor widget) { if (firstWidget != null) super.removeActor(firstWidget); firstWidget = widget; if (widget != null) super.addActor(widget); invalidate(); } /** @param widget May be null. */ public void setSecondWidget (Actor widget) { if (secondWidget != null) super.removeActor(secondWidget); secondWidget = widget; if (widget != null) super.addActor(widget); invalidate(); } public void addActor (Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget."); } public void addActorAt (int index, Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget."); } public void addActorBefore (Actor actorBefore, Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget."); } public void removeActor (Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget(null)."); } public void removeActorRecursive (Actor actor) { if (actor == firstWidget) setFirstWidget(null); else if (actor == firstWidget) setSecondWidget(null); else { if (firstWidget instanceof Group) ((Group)firstWidget).removeActorRecursive(actor); if (secondWidget instanceof Group) ((Group)secondWidget).removeActorRecursive(actor); } } /** The style for a splitpane, see {@link SplitPane}. * @author mzechner */ static public class SplitPaneStyle { public NinePatch handle; public SplitPaneStyle () { } public SplitPaneStyle (NinePatch handle) { this.handle = handle; } public SplitPaneStyle(SplitPaneStyle style) { this.handle = style.handle; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy