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

com.kotcrab.vis.ui.util.dialog.Dialogs Maven / Gradle / Ivy

There is a newer version: 1.5.3
Show newest version
/*
 * Copyright 2014-2016 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.util.dialog;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
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.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Cell;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.I18NBundle;
import com.badlogic.gdx.utils.StringBuilder;
import com.kotcrab.vis.ui.Locales;
import com.kotcrab.vis.ui.Sizes;
import com.kotcrab.vis.ui.VisUI;
import com.kotcrab.vis.ui.i18n.BundleText;
import com.kotcrab.vis.ui.util.InputValidator;
import com.kotcrab.vis.ui.util.TableUtils;
import com.kotcrab.vis.ui.util.Validators;
import com.kotcrab.vis.ui.widget.*;
import com.kotcrab.vis.ui.widget.ButtonBar.ButtonType;

/**
 * Utilities for displaying various type of dialogs. Equivalent of JOptionPane from Swing.
 * @author Kotcrab
 * @since 0.2.0
 */
public class Dialogs {
	private static final int BUTTON_OK = 1;
	private static final int BUTTON_DETAILS = 2;

	/**
	 * Dialog with given text and single OK button.
	 * @param title dialog title
	 */
	public static VisDialog showOKDialog (Stage stage, String title, String text) {
		final VisDialog dialog = new VisDialog(title);
		dialog.closeOnEscape();
		dialog.text(text);
		dialog.button(ButtonType.OK.getText()).padBottom(3);
		dialog.pack();
		dialog.centerWindow();
		dialog.addListener(new InputListener() {
			@Override
			public boolean keyDown (InputEvent event, int keycode) {
				if (keycode == Keys.ENTER) {
					dialog.fadeOut();
					return true;
				}
				return false;
			}
		});
		stage.addActor(dialog.fadeIn());
		return dialog;
	}

	/**
	 * Dialog with text and buttons like Yes, No, Cancel.
	 * @param title dialog title
	 * @param type specifies what types of buttons will this dialog have
	 * @param listener dialog buttons listener.
	 * @return dialog for the purpose of changing buttons text.
	 * @see OptionDialog
	 * @since 0.6.0
	 */
	public static OptionDialog showOptionDialog (Stage stage, String title, String text, OptionDialogType type, OptionDialogListener listener) {
		OptionDialog dialog = new OptionDialog(title, text, type, listener);
		stage.addActor(dialog.fadeIn());
		return dialog;
	}

	/**
	 * Dialog with title, text and n amount of buttons. If you need dialog with only buttons like Yes, No, Cancel then
	 * see {@link #showOptionDialog(Stage, String, String, OptionDialogType, OptionDialogListener)}.
	 * 

* @param title dialog title. * @param listener button listener for this dialog. This dialog is generic, listener type will depend on * 'returns' param type. * @since 0.7.0 */ public static ConfirmDialog showConfirmDialog (Stage stage, String title, String text, String[] buttons, T[] returns, ConfirmDialogListener listener) { ConfirmDialog dialog = new ConfirmDialog(title, text, buttons, returns, listener); stage.addActor(dialog.fadeIn()); return dialog; } /** * Dialog with text and text field for user input. Cannot be canceled. * @param title dialog title. * @param fieldTitle displayed before input field, may be null. * @param listener dialog buttons listener. */ public static InputDialog showInputDialog (Stage stage, String title, String fieldTitle, InputDialogListener listener) { InputDialog dialog = new InputDialog(title, fieldTitle, true, null, listener); stage.addActor(dialog.fadeIn()); return dialog; } /** * Dialog with text and text field for user input. Cannot be canceled. * @param title dialog title. * @param fieldTitle displayed before input field, may be null. * @param validator used to validate user input. Eg. limit input to integers only. See {@link Validators} for built-in validators. * @param listener dialog buttons listener. */ public static InputDialog showInputDialog (Stage stage, String title, String fieldTitle, InputValidator validator, InputDialogListener listener) { InputDialog dialog = new InputDialog(title, fieldTitle, true, validator, listener); stage.addActor(dialog.fadeIn()); return dialog; } /** * Dialog with text and text field for user input. * @param title dialog title. * @param cancelable if true dialog may be canceled by user. * @param fieldTitle displayed before input field, may be null. * @param listener dialog buttons listener. */ public static InputDialog showInputDialog (Stage stage, String title, String fieldTitle, boolean cancelable, InputDialogListener listener) { InputDialog dialog = new InputDialog(title, fieldTitle, cancelable, null, listener); stage.addActor(dialog.fadeIn()); return dialog; } /** * Dialog with text and text field for user input. * @param title dialog title * @param validator used to validate user input, can be used to easily limit input to int etc. See {@link Validators} for premade validators. * @param cancelable if true dialog may be canceled. * @param fieldTitle displayed before input field, may be null. */ public static InputDialog showInputDialog (Stage stage, String title, String fieldTitle, boolean cancelable, InputValidator validator, InputDialogListener listener) { InputDialog dialog = new InputDialog(title, fieldTitle, cancelable, validator, listener); stage.addActor(dialog.fadeIn()); return dialog; } /** Dialog with title "Error" and provided text. */ public static DetailsDialog showErrorDialog (Stage stage, String text) { return showErrorDialog(stage, text, (String) null); } /** Dialog with title "Error", provided text and exception stacktrace available after pressing 'Details' button. */ public static DetailsDialog showErrorDialog (Stage stage, String text, Exception exception) { if (exception == null) return showErrorDialog(stage, text, (String) null); else return showErrorDialog(stage, text, getStackTrace(exception)); } /** Dialog with title "Error", provided text, and provided details available after pressing 'Details' button. */ public static DetailsDialog showErrorDialog (Stage stage, String text, String details) { DetailsDialog dialog = new DetailsDialog(text, Text.ERROR.get(), details); stage.addActor(dialog.fadeIn()); return dialog; } /** Dialog with given title, provided text, and more details available after pressing 'Details' button. */ public static DetailsDialog showDetailsDialog (Stage stage, String text, String title, String details) { return showDetailsDialog(stage, text, title, details, false); } /** * Dialog with given title, provided text, and more details available after pressing 'Details' button. * @param expandDetails if true details will be visible without need to press 'Details' button */ public static DetailsDialog showDetailsDialog (Stage stage, String text, String title, String details, boolean expandDetails) { DetailsDialog dialog = new DetailsDialog(text, title, details); dialog.setDetailsVisible(expandDetails); stage.addActor(dialog.fadeIn()); return dialog; } private static VisScrollPane createScrollPane (Actor widget) { VisScrollPane scrollPane = new VisScrollPane(widget); scrollPane.setOverscroll(false, true); scrollPane.setFadeScrollBars(false); return scrollPane; } private static String getStackTrace (Throwable throwable) { StringBuilder builder = new StringBuilder(); getStackTrace(throwable, builder); return builder.toString(); } private static void getStackTrace (Throwable throwable, StringBuilder builder) { String msg = throwable.getMessage(); if (msg != null) { builder.append(msg); builder.append("\n\n"); } for (StackTraceElement element : throwable.getStackTrace()) { builder.append(element); builder.append("\n"); } if (throwable.getCause() != null) { builder.append("\nCaused by: "); getStackTrace(throwable.getCause(), builder); } } public enum OptionDialogType { YES_NO, YES_NO_CANCEL, YES_CANCEL } /** * Dialog with input field and optional {@link InputValidator}. Can be used directly although you should use {@link Dialogs} * showInputDialog methods. */ public static class InputDialog extends VisWindow { private InputDialogListener listener; private VisTextField field; private VisTextButton okButton; private VisTextButton cancelButton; public InputDialog (String title, String fieldTitle, boolean cancelable, InputValidator validator, InputDialogListener listener) { super(title); this.listener = listener; TableUtils.setSpacingDefaults(this); setModal(true); if (cancelable) { addCloseButton(); closeOnEscape(); } ButtonBar buttonBar = new ButtonBar(); buttonBar.setIgnoreSpacing(true); buttonBar.setButton(ButtonType.CANCEL, cancelButton = new VisTextButton(ButtonType.CANCEL.getText())); buttonBar.setButton(ButtonType.OK, okButton = new VisTextButton(ButtonType.OK.getText())); VisTable fieldTable = new VisTable(true); if (validator == null) field = new VisTextField(); else field = new VisValidatableTextField(validator); if (fieldTitle != null) fieldTable.add(new VisLabel(fieldTitle)); fieldTable.add(field).expand().fill(); add(fieldTable).padTop(3).spaceBottom(4); row(); add(buttonBar.createTable()).padBottom(3); addListeners(); if (validator != null) { addValidatableFieldListener(field); okButton.setDisabled(!field.isInputValid()); } pack(); centerWindow(); } @Override protected void close () { super.close(); listener.canceled(); } @Override protected void setStage (Stage stage) { super.setStage(stage); if (stage != null) field.focusField(); } public InputDialog setText (String text) { return setText(text, false); } /** @param selectText if true text will be selected (this can be useful if you want to allow user quickly erase all text). */ public InputDialog setText (String text, boolean selectText) { field.setText(text); field.setCursorPosition(text.length()); if (selectText) { field.selectAll(); } return this; } private InputDialog addValidatableFieldListener (final VisTextField field) { field.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { if (field.isInputValid()) { okButton.setDisabled(false); } else { okButton.setDisabled(true); } } }); return this; } private void addListeners () { okButton.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { listener.finished(field.getText()); fadeOut(); } }); cancelButton.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { close(); } }); field.addListener(new InputListener() { @Override public boolean keyDown (InputEvent event, int keycode) { if (keycode == Keys.ENTER && okButton.isDisabled() == false) { listener.finished(field.getText()); fadeOut(); } return super.keyDown(event, keycode); } }); } } /** * Dialog with text and buttons like Yes, No, Cancel. Can be used directly although you should use {@link Dialogs} * showOptionDialog methods. */ public static class OptionDialog extends VisWindow { //NOTE: when updating this class, don't forget about Editor's DisableableOptionDialog private final ButtonBar buttonBar; public OptionDialog (String title, String text, OptionDialogType type, final OptionDialogListener listener) { super(title); setModal(true); add(new VisLabel(text, Align.center)); row(); defaults().space(6); defaults().padBottom(3); buttonBar = new ButtonBar(); buttonBar.setIgnoreSpacing(true); ChangeListener yesBtnListener = new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { listener.yes(); fadeOut(); } }; ChangeListener noBtnListener = new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { listener.no(); fadeOut(); } }; ChangeListener cancelBtnListener = new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { listener.cancel(); fadeOut(); } }; switch (type) { case YES_NO: buttonBar.setButton(ButtonType.YES, yesBtnListener); buttonBar.setButton(ButtonType.NO, noBtnListener); break; case YES_CANCEL: buttonBar.setButton(ButtonType.YES, yesBtnListener); buttonBar.setButton(ButtonType.CANCEL, cancelBtnListener); break; case YES_NO_CANCEL: buttonBar.setButton(ButtonType.YES, yesBtnListener); buttonBar.setButton(ButtonType.NO, noBtnListener); buttonBar.setButton(ButtonType.CANCEL, cancelBtnListener); break; } add(buttonBar.createTable()); pack(); centerWindow(); } public OptionDialog setNoButtonText (String text) { buttonBar.getTextButton(ButtonType.NO).setText(text); pack(); return this; } public OptionDialog setYesButtonText (String text) { buttonBar.getTextButton(ButtonType.YES).setText(text); pack(); return this; } public OptionDialog setCancelButtonText (String text) { buttonBar.getTextButton(ButtonType.CANCEL).setText(text); pack(); return this; } } /** * Dialog with text and exception stacktrace available after pressing Details button. * Can be used directly although you should use {@link Dialogs} showErrorDialog methods. */ public static class DetailsDialog extends VisDialog { private VisTable detailsTable = new VisTable(true); private Cell detailsCell; private boolean detailsVisible; private VisTextButton copyButton; private VisLabel detailsLabel; public DetailsDialog (String text, String title, String details) { super(title); text(text); if (details != null) { copyButton = new VisTextButton(Text.COPY.get()); detailsLabel = new VisLabel(details); Sizes sizes = VisUI.getSizes(); copyButton.addListener(new ChangeListener() { @Override public void changed (ChangeEvent event, Actor actor) { Gdx.app.getClipboard().setContents((detailsLabel.getText().toString())); copyButton.setText(Text.COPIED.get()); } }); detailsTable.add(new VisLabel(Text.DETAILS_COLON.get())).left().expand().padTop(6); detailsTable.add(copyButton); detailsTable.row(); VisTable detailsTable = new VisTable(); detailsTable.add(detailsLabel).top().expand().fillX(); this.detailsTable.add(createScrollPane(detailsTable)).colspan(2).minWidth(600 * sizes.scaleFactor).height(300 * sizes.scaleFactor); getContentTable().row(); detailsCell = getContentTable().add(this.detailsTable); detailsCell.setActor(null); button(Text.DETAILS.get(), BUTTON_DETAILS); } button(ButtonType.OK.getText(), BUTTON_OK).padBottom(3); pack(); centerWindow(); } @Override protected void result (Object object) { int result = (Integer) object; if (result == BUTTON_DETAILS) { setDetailsVisible(!detailsVisible); cancel(); } } public void setWrapDetails (boolean wrap) { detailsLabel.setWrap(wrap); } public void setCopyDetailsButtonVisible (boolean visible) { copyButton.setVisible(visible); } public boolean isCopyDetailsButtonVisible () { return copyButton.isVisible(); } /** * Changes visibility of details pane. Note that Window must be added to Stage or Window won't be packed properly and * it's size will be wrong. If Window is not added to Stage packing will be performed next frame, if it is still * not added at that point, Window size will be incorrect. */ public void setDetailsVisible (boolean visible) { if (detailsVisible == visible) return; detailsVisible = visible; detailsCell.setActor(detailsCell.hasActor() ? null : detailsTable); //looks like Stage is required to properly pack window //if it's null do packing next frame and hope that window have been already added to Stage at that point if (getStage() == null) { Gdx.app.postRunnable(new Runnable() { @Override public void run () { pack(); centerWindow(); } }); } else { pack(); centerWindow(); } } public boolean isDetailsVisible () { return detailsVisible; } } /** * Dialog with title, text and n amount of buttons. Can be used directly although you should use {@link Dialogs} * showConfirmDialog methods. * @author Javier * @author Kotcrab */ public static class ConfirmDialog extends VisDialog { private ConfirmDialogListener listener; public ConfirmDialog (String title, String text, String[] buttons, T[] returns, ConfirmDialogListener listener) { super(title); if (buttons.length != returns.length) { throw new IllegalStateException("buttons.length must be equal to returns.length"); } this.listener = listener; text(new VisLabel(text, Align.center)); defaults().padBottom(3); for (int i = 0; i < buttons.length; i++) { button(buttons[i], returns[i]); } padBottom(3); pack(); centerWindow(); } @Override protected void result (Object object) { listener.result((T) object); } } /** {@link Dialogs} I18N properties. */ private enum Text implements BundleText { DETAILS("details"), DETAILS_COLON("detailsColon"), COPY("copy"), COPIED("copied"), ERROR("error"); private final String name; Text (final String name) { this.name = name; } private static I18NBundle getBundle () { return Locales.getDialogsBundle(); } @Override public final String getName () { return name; } @Override public final String get () { return getBundle().get(name); } @Override public final String format () { return getBundle().format(name); } @Override public final String format (final Object... arguments) { return getBundle().format(name, arguments); } @Override public final String toString () { return get(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy