/******************************************************************************* * Copyright 2014 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 Roguelike.UI; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Touchable; import com.badlogic.gdx.scenes.scene2d.ui.Cell; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Stack; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.Pools; /** A {@code TabbedPane} widget not full featured but somewhat reusable. * * @author davebaol */ public class TabPanel extends Table { private TabPanelStyle style; public Table tabTitleTable; Stack tabBodyStack; int selectedIndex; int tabTitleAlign = Align.left; /** Creates a {@code TabbedPane} using the specified skin. * @param skin the skin */ public TabPanel( Skin skin ) { super(skin); initialize(skin.get(TabPanelStyle.class)); } /** Creates a {@code TabbedPane} using the specified skin and alignment. * @param skin the skin * @param tabTitleAlign the alignment for tab titles. Must be one of {@link Align#left}, {@link Align#center} or * {@link Align#right}. */ public TabPanel( Skin skin, int tabTitleAlign ) { super(skin); this.tabTitleAlign = tabTitleAlign; initialize(skin.get(TabPanelStyle.class)); } /** Creates a {@code TabbedPane} using the specified skin and style name. * @param skin the skin * @param styleName the style name */ public TabPanel( Skin skin, String styleName ) { super(skin); initialize(skin.get(styleName, TabPanelStyle.class)); } /** Creates a {@code TabbedPane} using the specified skin, style name and alignment. * @param skin the skin * @param styleName the style name * @param tabTitleAlign the alignment for tab titles. Must be one of {@link Align#left}, {@link Align#center} or * {@link Align#right}. */ public TabPanel( Skin skin, String styleName, int tabTitleAlign ) { super(skin); this.tabTitleAlign = tabTitleAlign; initialize(skin.get(styleName, TabPanelStyle.class)); } public TabPanel( TabPanelStyle style ) { initialize(style); } /** Creates a {@code TabbedPane} using the specified style and alignment. * @param style the style * @param tabTitleAlign the alignment for tab titles. Must be one of {@link Align#left}, {@link Align#center} or * {@link Align#right}. */ public TabPanel( TabPanelStyle style, int tabTitleAlign ) { this.tabTitleAlign = tabTitleAlign; initialize(style); } /** Creates a {@code TabbedPane} without setting the style or size. At least a style must be set before using this tabbed pane. */ public TabPanel() { initialize(); } private void initialize (TabPanelStyle style) { setStyle(style); setSize(getPrefWidth(), getPrefHeight()); initialize(); } private void initialize () { setTouchable(Touchable.enabled); tabTitleTable = new Table(); tabBodyStack = new Stack(); selectedIndex = -1; // Create 1st row Cell<?> leftCell = add(new Image(style.titleBegin)); Cell<?> midCell = add(tabTitleTable); Cell<?> rightCell = add(new Image(style.titleEnd)); switch (tabTitleAlign) { case Align.left: leftCell.width(((Image)leftCell.getActor()).getWidth()).bottom(); midCell.left(); rightCell.expandX().fillX().bottom(); break; case Align.right: leftCell.expandX().fillX().bottom(); midCell.right(); rightCell.width(((Image)rightCell.getActor()).getWidth()).bottom(); break; case Align.center: leftCell.expandX().fillX().bottom(); midCell.center(); rightCell.expandX().fillX().bottom(); break; default: throw new IllegalArgumentException("TabbedPane align must be one of left, center, right"); } // Create 2nd row row(); Table t = new Table(); t.setBackground(style.bodyBackground); t.add(tabBodyStack).expand().fill(); add(t).colspan(3).expand().fill(); } @Override public Table debug () { tabTitleTable.debug(); return super.debug(); } public void setStyle (TabPanelStyle style) { if (style == null) throw new IllegalArgumentException("style cannot be null."); this.style = style; invalidateHierarchy(); } /** Returns the tabbed pane's style. Modifying the returned style may not have an effect until * {@link #setStyle(TabPanelStyle)} is called. */ public TabPanelStyle getStyle () { return style; } public void addTab (String title, Actor actor) { int index = tabTitleTable.getCells().size; final TabTitleButton button = new TabTitleButton(index, title, style); button.addListener(new ClickListener() { @Override public void clicked (InputEvent event, float x, float y) { setSelectedIndex(button.index); } }); tabTitleTable.add(button); // .uniform().fill(); // uniform gives tabs the same size tabBodyStack.add(actor); // Make sure the 1st tab is selected even after adding the tab // TODO // CAUTION: if you've added a ChangeListener before adding the tab // the following lines will fire 2 ChangeEvents. setSelectedIndex(index); setSelectedIndex(0); } public int getSelectedIndex () { return selectedIndex; } public void setSelectedIndex (int index) { if (selectedIndex == index) return; int tabs = tabTitleTable.getCells().size; if (selectedIndex >= 0 && selectedIndex < tabs) { setSelectedTab(false); } this.selectedIndex = index; if (selectedIndex >= 0 && selectedIndex < tabs) { setSelectedTab(true); } fireStateChanged(); } private void setSelectedTab (boolean value) { TabTitleButton tabTitleButton = ((TabTitleButton)tabTitleTable.getCells().get(selectedIndex).getActor()); tabTitleButton.setDisabled(value); // Can't toggle the selected tab tabTitleButton.setChecked(value); tabBodyStack.getChildren().get(selectedIndex).setVisible(value); } /** Sends a ChangeEvent, with this TabbedPane as the target, to each registered listener. This method is called each time there * is a change to the selected index. */ protected void fireStateChanged () { ChangeEvent changeEvent = Pools.obtain(ChangeEvent.class); changeEvent.setBubbles(false); fire(changeEvent); Pools.free(changeEvent); } private static class TabTitleButton extends TextButton { private int index; private TabTitleButton (int index, String text, TabPanelStyle style) { super(text, toTextButtonStyle(style)); this.index = index; } private static TextButtonStyle toTextButtonStyle (TabPanelStyle style) { TextButtonStyle buttonStyle = new TextButtonStyle(style.titleButtonUnselected, null, style.titleButtonSelected, style.font); buttonStyle.fontColor = style.fontColor; buttonStyle.downFontColor = style.downFontColor; buttonStyle.overFontColor = style.overFontColor; buttonStyle.checkedFontColor = style.checkedFontColor; buttonStyle.checkedOverFontColor = style.checkedOverFontColor; buttonStyle.disabledFontColor = style.disabledFontColor; return buttonStyle; } } /** The style for a {@link TabPanel}. **/ static public class TabPanelStyle { public Drawable titleBegin, titleEnd, bodyBackground; public Drawable titleButtonSelected, titleButtonUnselected; public BitmapFont font; /** Optional. */ public Color fontColor, downFontColor, overFontColor, checkedFontColor, checkedOverFontColor, disabledFontColor; public TabPanelStyle () { } public TabPanelStyle (Drawable titleBegin, Drawable titleEnd, Drawable bodyBackground, Drawable titleButtonSelected, Drawable titleButtonUnselected, BitmapFont font) { this.titleBegin = titleBegin; this.titleEnd = titleEnd; this.bodyBackground = bodyBackground; this.titleButtonSelected = titleButtonSelected; this.titleButtonUnselected = titleButtonUnselected; this.font = font; } public TabPanelStyle (TabPanelStyle style) { this.titleBegin = style.titleBegin; this.titleEnd = style.titleEnd; this.bodyBackground = style.bodyBackground; this.titleButtonSelected = style.titleButtonSelected; this.titleButtonUnselected = style.titleButtonUnselected; this.font = style.font; if (style.fontColor != null) this.fontColor = new Color(style.fontColor); if (style.downFontColor != null) this.downFontColor = new Color(style.downFontColor); if (style.overFontColor != null) this.overFontColor = new Color(style.overFontColor); if (style.checkedFontColor != null) this.checkedFontColor = new Color(style.checkedFontColor); if (style.checkedOverFontColor != null) this.checkedFontColor = new Color(style.checkedOverFontColor); if (style.disabledFontColor != null) this.disabledFontColor = new Color(style.disabledFontColor); } } }