Package com.badlogic.gdx.scenes.scene2d.ui

Source Code of com.badlogic.gdx.scenes.scene2d.ui.SplitPane

/*******************************************************************************
* 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.
* <p>
* 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;
    }
  }
}
TOP

Related Classes of com.badlogic.gdx.scenes.scene2d.ui.SplitPane

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.