SimpleJavaEngine/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedPanelComponent.java

339 lines
8.8 KiB
Java

package speiger.src.coreengine.rendering.gui.components;
import speiger.src.collections.objects.functions.function.Object2FloatFunction;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.rendering.gui.GuiComponent;
import speiger.src.coreengine.rendering.gui.base.IButtonComponent;
import speiger.src.coreengine.rendering.gui.helper.Align;
import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.gui.helper.constrains.DynamicConstrain;
import speiger.src.coreengine.utils.functions.FloatSupplier;
public class TabbedPanelComponent extends PanelComponent
{
PanelComponent selection = new PanelComponent();
ObjectList<Tab> tabs = new ObjectArrayList<>();
int selectedTab = -1;
float tabScale = 1F;
Facing facing;
int backgroundColor = ColorUtils.GRAY;
int unselectedColor = ColorUtils.GRAY;
int selectedColor = ColorUtils.DARK_GRAY;
float padding = 30F;
public TabbedPanelComponent()
{
this(Facing.NORTH);
}
public TabbedPanelComponent(Facing facing)
{
this(0F, 0F, 0F, 0F, facing);
}
public TabbedPanelComponent(float x, float y, float width, float height)
{
this(x, y, width, height, Facing.NORTH);
}
public TabbedPanelComponent(float x, float y, float width, float height, Facing facing)
{
super(x, y, width, height);
this.facing = facing;
}
public TabbedPanelComponent setFacing(Facing facing)
{
this.facing = facing;
updateConstrains(selection, createView());
for(Tab tab : tabs)
{
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
updateConstrains(tab.getPanel(), createPanel());
}
onChanged(true);
return this;
}
public TabbedPanelComponent setPadding(float padding)
{
this.padding = padding;
for(Tab tab : tabs)
{
tab.updatePadding();
}
onChanged(true);
return this;
}
public Facing getFacing()
{
return facing;
}
public PanelComponent addTab(String name)
{
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
tabs.add(newTab);
if(selectedTab == -1) {
selectedTab = tabs.size()-1;
newTab.getPanel().setVisible(true);
}
newTab.onAction(() -> selectTab(newTab));
selection.addChild(newTab, createConstraint(newTab));
addChild(newTab.getPanel(), createPanel());
onChanged(true);
return newTab.getPanel();
}
public int findTab(String name)
{
for(int i = 0,m=tabs.size();i<m;i++) {
if(tabs.get(i).name.equals(name)) return i;
}
return -1;
}
public int getActiveIndex()
{
return selectedTab;
}
public PanelComponent getActiveTab()
{
return selectedTab == -1 ? null : tabs.get(selectedTab).getPanel();
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
getRenderer().drawQuad(selection.getBox(), backgroundColor);
return true;
}
@Override
public void init()
{
addChild(selection, createView());
super.init();
}
@Override
protected void repaint()
{
if(facing.isZAxis())
{
float room = getBox().getBaseWidth();
float requiredSpace = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
float width = tab.getWidth() * tab.getTextScale();
if(i == selectedTab) room -= width;
else requiredSpace += width;
}
tabScale = Math.min(1F, room / requiredSpace);
}
else
{
tabScale = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
}
tabScale *= getBox().getScale();
tabScale += 1F;
}
}
protected Constrains createView()
{
switch(facing)
{
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createPanel()
{
switch(facing)
{
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createConstraint(Tab tab)
{
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
}
protected void selectTab(Tab tab)
{
selectTab(tabs.indexOf(tab));
}
public boolean selectTab(int index)
{
if(index < 0 || index >= tabs.size()) return false;
if(selectedTab == index) return false;
if(selectedTab != -1) tabs.get(selectedTab).getPanel().setVisible(false);
selectedTab = index;
tabs.get(selectedTab).getPanel().setVisible(true);
onChanged(true);
return true;
}
protected float getOffset(Tab tab)
{
int index = tabs.indexOf(tab);
float offset = 0F;
for(int i = 0;i<index;i++)
{
Tab entry = tabs.get(i);
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
else offset += tab.getBox().getBaseHeight();
}
return offset;
}
protected float getPanelOffset()
{
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
}
protected float getPanelWidth()
{
return tabScale + 0.25F;
}
protected float getXOffset()
{
return tabScale + 0.25F;
}
protected float getWidth(Tab tab)
{
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
}
private static class DynamicTab implements FloatSupplier
{
Tab tab;
Object2FloatFunction<Tab> function;
public DynamicTab(Tab tab, Object2FloatFunction<Tab> function)
{
this.tab = tab;
this.function = function;
}
@Override
public float getAsFloat()
{
return function.getFloat(tab);
}
}
private class Tab extends GuiComponent implements IButtonComponent
{
String name;
float width = -1F;
TextComponent comp;
PanelComponent panel = new PanelComponent().setScissors(true).setVisible(false).cast();
public Tab(String name)
{
super(0F, 0F, 100F, 7.5F);
this.name = name;
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
setFlag(FLAG_SUPPORT_BINDING);
}
public Tab align(Align align)
{
comp.horizontal(align);
return this;
}
public void updatePadding()
{
if(getGui() != null) width = getFont().width(name)+padding;
}
@Override
public void init()
{
addChild(comp, Constrains.parent());
updatePadding();
}
public float getWidth()
{
return width;
}
public float getTextScale()
{
return comp.getTextScale();
}
@Override
protected void repaint()
{
String s = name;
float scale = comp.getTextScale();
float width = (this.width-padding)*scale;
float desiredWidth = getBox().getBaseWidth();
if(width > desiredWidth) {
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
s = s.substring(0, s.length()-1);
}
comp.setText(s+"...");
return;
}
comp.setText(s);
}
public PanelComponent getPanel()
{
return panel;
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
boolean notSelected = tabs.indexOf(this) != selectedTab;
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
return true;
}
@Override
public void onRelease(int button, int mouseX, int mouseY)
{
notifyListeners(LISTENER_USER_ACTION);
}
@Override
protected boolean onUserKey()
{
notifyListeners(LISTENER_USER_ACTION);
return true;
}
}
}