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

pl.kotcrab.vis.ui.widget.VisSplitPane Maven / Gradle / Ivy

There is a newer version: 0.3.1
Show newest version
/*******************************************************************************
 * Copyright 2014 Pawel Pastuszak
 *
 * 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 pl.kotcrab.vis.ui.widget;

import pl.kotcrab.vis.ui.FocusManager;
import pl.kotcrab.vis.ui.VisUI;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
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.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.SplitPane.SplitPaneStyle;
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.Layout;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.GdxRuntimeException;

/** A container that contains two widgets and is divided either horizontally or vertically. The user may resize the widgets. The
 * child widgets are always sized to fill their 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 * @author Pawel Pastuszak */ public class VisSplitPane extends WidgetGroup { SplitPaneStyle style; private Actor firstWidget, secondWidget; boolean vertical; float splitAmount = 0.5f, minAmount, maxAmount = 1; // private float oldSplitAmount; private Rectangle firstWidgetBounds = new Rectangle(); private Rectangle secondWidgetBounds = new Rectangle(); Rectangle handleBounds = new Rectangle(); private Rectangle firstScissors = new Rectangle(); private Rectangle secondScissors = new Rectangle(); Vector2 lastPoint = new Vector2(); Vector2 handlePosition = new Vector2(); /** @param firstWidget May be null. * @param secondWidget May be null. */ public VisSplitPane (Actor firstWidget, Actor secondWidget, boolean vertical) { this(firstWidget, secondWidget, vertical, "default-" + (vertical ? "vertical" : "horizontal")); } /** @param firstWidget May be null. * @param secondWidget May be null. */ public VisSplitPane (Actor firstWidget, Actor secondWidget, boolean vertical, String styleName) { this(firstWidget, secondWidget, vertical, VisUI.skin.get(styleName, SplitPaneStyle.class)); } /** @param firstWidget May be null. * @param secondWidget May be null. */ public VisSplitPane (Actor firstWidget, Actor secondWidget, boolean vertical, SplitPaneStyle style) { this.firstWidget = firstWidget; this.secondWidget = secondWidget; this.vertical = vertical; setStyle(style); setFirstWidget(firstWidget); setSecondWidget(secondWidget); setSize(getPrefWidth(), getPrefHeight()); initialize(); } private void initialize () { addListener(new InputListener() { int draggingPointer = -1; @Override public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { if (draggingPointer != -1) return false; if (pointer == 0 && button != 0) return false; if (handleBounds.contains(x, y)) { FocusManager.getFocus(); draggingPointer = pointer; lastPoint.set(x, y); handlePosition.set(handleBounds.x, handleBounds.y); return true; } return false; } @Override public void touchUp (InputEvent event, float x, float y, int pointer, int button) { if (pointer == draggingPointer) draggingPointer = -1; } @Override public void touchDragged (InputEvent event, float x, float y, int pointer) { if (pointer != draggingPointer) return; Drawable handle = style.handle; if (!vertical) { float delta = x - lastPoint.x; float availWidth = getWidth() - handle.getMinWidth(); 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 = getHeight() - handle.getMinHeight(); 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(); } }); } 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(); Actor firstWidget = this.firstWidget; if (firstWidget != null) { Rectangle firstWidgetBounds = this.firstWidgetBounds; firstWidget.setBounds(firstWidgetBounds.x, firstWidgetBounds.y, firstWidgetBounds.width, firstWidgetBounds.height); if (firstWidget instanceof Layout) ((Layout)firstWidget).validate(); } Actor secondWidget = this.secondWidget; if (secondWidget != null) { Rectangle secondWidgetBounds = this.secondWidgetBounds; secondWidget.setBounds(secondWidgetBounds.x, secondWidgetBounds.y, secondWidgetBounds.width, secondWidgetBounds.height); if (secondWidget instanceof Layout) ((Layout)secondWidget).validate(); } } @Override public float getPrefWidth () { float width = 0; if (firstWidget != null) width = firstWidget instanceof Layout ? ((Layout)firstWidget).getPrefWidth() : firstWidget.getWidth(); if (secondWidget != null) width += secondWidget instanceof Layout ? ((Layout)secondWidget).getPrefWidth() : secondWidget.getWidth(); if (!vertical) width += style.handle.getMinWidth(); return width; } @Override public float getPrefHeight () { float height = 0; if (firstWidget != null) height = firstWidget instanceof Layout ? ((Layout)firstWidget).getPrefHeight() : firstWidget.getHeight(); if (secondWidget != null) height += secondWidget instanceof Layout ? ((Layout)secondWidget).getPrefHeight() : secondWidget.getHeight(); if (vertical) height += style.handle.getMinHeight(); return height; } @Override public float getMinWidth () { return 0; } @Override public float getMinHeight () { return 0; } public void setVertical (boolean vertical) { this.vertical = vertical; } private void calculateHorizBoundsAndPositions () { Drawable handle = style.handle; float height = getHeight(); float availWidth = getWidth() - handle.getMinWidth(); float leftAreaWidth = (int)(availWidth * splitAmount); float rightAreaWidth = availWidth - leftAreaWidth; float handleWidth = handle.getMinWidth(); firstWidgetBounds.set(0, 0, leftAreaWidth, height); secondWidgetBounds.set(leftAreaWidth + handleWidth, 0, rightAreaWidth, height); handleBounds.set(leftAreaWidth, 0, handleWidth, height); } private void calculateVertBoundsAndPositions () { Drawable handle = style.handle; float width = getWidth(); float height = getHeight(); float availHeight = height - handle.getMinHeight(); float topAreaHeight = (int)(availHeight * splitAmount); float bottomAreaHeight = availHeight - topAreaHeight; float handleHeight = handle.getMinHeight(); firstWidgetBounds.set(0, height - topAreaHeight, width, topAreaHeight); secondWidgetBounds.set(0, 0, width, bottomAreaHeight); handleBounds.set(0, bottomAreaHeight, width, handleHeight); } @Override public void draw (Batch batch, float parentAlpha) { validate(); Color color = getColor(); Drawable handle = style.handle; applyTransform(batch, computeTransform()); // Matrix4 transform = batch.getTransformMatrix(); if (firstWidget != null) { getStage().calculateScissors(firstWidgetBounds, firstScissors); if (ScissorStack.pushScissors(firstScissors)) { if (firstWidget.isVisible()) firstWidget.draw(batch, parentAlpha * color.a); batch.flush(); ScissorStack.popScissors(); } } if (secondWidget != null) { getStage().calculateScissors(secondWidgetBounds, secondScissors); if (ScissorStack.pushScissors(secondScissors)) { if (secondWidget.isVisible()) secondWidget.draw(batch, parentAlpha * color.a); batch.flush(); ScissorStack.popScissors(); } } // changed, original was batch.setColor(color.r, color.g, color.b, color.a); batch.setColor(color.r, color.g, color.b, parentAlpha * color.a); handle.draw(batch, handleBounds.x, handleBounds.y, handleBounds.width, handleBounds.height); resetTransform(batch); } /** @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(); } @Override public void addActor (Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget."); } @Override public void addActorAt (int index, Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget."); } @Override public void addActorBefore (Actor actorBefore, Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget."); } @Override public boolean removeActor (Actor actor) { throw new UnsupportedOperationException("Use ScrollPane#setWidget(null)."); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy