New weighted constrained
This commit is contained in:
parent
bfe426f11e
commit
dce550da0d
@ -18,10 +18,10 @@ import speiger.src.coreengine.math.vector.matrix.Matrix4f;
|
||||
import speiger.src.coreengine.rendering.gui.font.Font;
|
||||
import speiger.src.coreengine.rendering.gui.font.FontManager;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.GlythBaker;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.GlythBaker;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
|
||||
import speiger.src.coreengine.rendering.input.devices.FileDrop;
|
||||
|
@ -5,6 +5,7 @@ import java.util.function.Consumer;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.rendering.gui.animation.GuiAnimator;
|
||||
import speiger.src.coreengine.rendering.gui.layout.constraints.ConstrainedContext;
|
||||
import speiger.src.coreengine.rendering.gui.layout.constraints.ConstraintContainer;
|
||||
import speiger.src.coreengine.rendering.gui.renderer.IUIRenderer;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
|
||||
@ -21,6 +22,7 @@ public abstract non-sealed class GuiComponent extends FlagObject implements ICas
|
||||
final IGuiBox box;
|
||||
IComponentScreen screen;
|
||||
ConstraintContainer constraints;
|
||||
ConstrainedContext constraintedContext = new ConstrainedContext();
|
||||
GuiAnimator animator;
|
||||
GuiComponent parent;
|
||||
List<GuiComponent> children = new ObjectArrayList<>();
|
||||
@ -102,12 +104,20 @@ public abstract non-sealed class GuiComponent extends FlagObject implements ICas
|
||||
return true;
|
||||
}
|
||||
|
||||
private ConstrainedContext parentContext() {
|
||||
return parent != null ? parent.constraintedContext : null;
|
||||
}
|
||||
|
||||
public GuiComponent withConstraints(ConstraintContainer container) {
|
||||
this.constraints = container;
|
||||
if((screen != null || parent != null) && constraints != null) constraints.apply(this, parent);
|
||||
if((screen != null || parent != null) && constraints != null) constraints.apply(this, parent, parentContext());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConstraintContainer constraint() {
|
||||
return constraints;
|
||||
}
|
||||
|
||||
public GuiComponent addChild(GuiComponent child) {
|
||||
if(child.parent != null) throw new IllegalArgumentException("A Child can not have multiple parents");
|
||||
child.parent = this;
|
||||
@ -155,13 +165,16 @@ public abstract non-sealed class GuiComponent extends FlagObject implements ICas
|
||||
}
|
||||
|
||||
public void onChanged(boolean repaint) {
|
||||
if(constraints != null) constraints.apply(this, parent);
|
||||
if(constraints != null) constraints.apply(this, parent, parentContext());
|
||||
if(animator != null) animator.apply();
|
||||
box.onChanged();
|
||||
constraintedContext.update(this, children);
|
||||
notifyListeners(LISTENER_ON_CHANGE);
|
||||
if(repaint) repaint();
|
||||
if(children.isEmpty()) return;
|
||||
int index = 0;
|
||||
for(GuiComponent comp : children) {
|
||||
constraintedContext.setCurrent(index++);
|
||||
comp.onChanged(repaint);
|
||||
}
|
||||
}
|
||||
@ -173,6 +186,7 @@ public abstract non-sealed class GuiComponent extends FlagObject implements ICas
|
||||
public IGuiBox getBox() { return box; }
|
||||
public IInteractable interactContainer() { return interactions; }
|
||||
|
||||
|
||||
@Override
|
||||
public GuiComponent set(float x, float y) {
|
||||
if(box.getBaseX() != x || box.getBaseY() != y) {
|
||||
|
@ -0,0 +1,89 @@
|
||||
package speiger.src.coreengine.rendering.gui.layout.constraints;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import speiger.src.coreengine.rendering.gui.components.base.GuiComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
|
||||
|
||||
public class ConstrainedContext {
|
||||
float[] bounds;
|
||||
float[] weights;
|
||||
boolean locked = false;
|
||||
int current;
|
||||
|
||||
public void update(GuiComponent owner, List<GuiComponent> children) {
|
||||
locked = false;
|
||||
bounds = new float[children.size()*2];
|
||||
weights = new float[children.size()*2];
|
||||
for(int i = 0,m=children.size();i<m;i++) {
|
||||
current = i;
|
||||
GuiComponent component = children.get(i);
|
||||
if(component.constraint() == null) {
|
||||
applyDefault(component);
|
||||
continue;
|
||||
}
|
||||
component.constraint().fetch(component, owner, this);
|
||||
}
|
||||
locked = true;
|
||||
float[] totals = new float[4];
|
||||
for(int i = 0,m=children.size();i<m;i++) {
|
||||
totals[0] += bounds[i*2];
|
||||
totals[1] += bounds[i*2+1];
|
||||
totals[2] += weights[i*2];
|
||||
totals[3] += weights[i*2+1];
|
||||
}
|
||||
IGuiBox box = owner.getBox();
|
||||
totals[0] -= box.getBaseWidth();
|
||||
totals[1] -= box.getBaseHeight();
|
||||
if(totals[2] > 0F) {
|
||||
float scale = 1F / totals[2];
|
||||
for(int i = 0,m=children.size();i<m;i++) {
|
||||
float value = weights[i*2];
|
||||
if(value <= 0F) continue;
|
||||
bounds[i*2] = value * scale;
|
||||
}
|
||||
}
|
||||
if(totals[3] > 0F) {
|
||||
float scale = 1F / totals[3];
|
||||
for(int i = 0,m=children.size();i<m;i++) {
|
||||
float value = weights[i*2+1];
|
||||
if(value <= 0) continue;
|
||||
bounds[i*2+1] = value * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCurrent(int index) {
|
||||
if(!locked) throw new IllegalStateException("Cursor can only be moved when its in read mode!");
|
||||
current = index;
|
||||
}
|
||||
|
||||
public float getOffset(boolean width) {
|
||||
if(!locked) throw new IllegalStateException("You can't read during write!");
|
||||
float total = 0F;
|
||||
for(int i = 0;i<current;i++) {
|
||||
total += bounds[i*2+(width ? 0 : 1)];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
public float get(boolean width) {
|
||||
if(!locked) throw new IllegalStateException("You can't read during write!");
|
||||
return bounds[current*2+(width ? 0 : 1)];
|
||||
}
|
||||
|
||||
private void applyDefault(GuiComponent component) {
|
||||
addBound(component.getWidth(), true);
|
||||
addBound(component.getHeight(), true);
|
||||
}
|
||||
|
||||
public void addWeight(float weight, boolean width) {
|
||||
if(locked) return;
|
||||
weights[current*2+(width ? 0 : 1)] = weight;
|
||||
}
|
||||
|
||||
public void addBound(float bound, boolean width) {
|
||||
if(locked) return;
|
||||
bounds[current*2+(width ? 0 : 1)] = bound;
|
||||
}
|
||||
}
|
@ -9,10 +9,21 @@ public class ConstraintContainer {
|
||||
|
||||
private ConstraintContainer() {}
|
||||
|
||||
public void apply(GuiComponent owner, GuiComponent parent) {
|
||||
public void apply(GuiComponent owner, GuiComponent parent, ConstrainedContext context) {
|
||||
for(int i = 0;i<4;i++) {
|
||||
if(constraints[i] == null) continue;
|
||||
constraints[i].apply(owner, parent, Target.by(i));
|
||||
constraints[i].apply(owner, parent, Target.by(i), context);
|
||||
}
|
||||
}
|
||||
|
||||
public void fetch(GuiComponent owner, GuiComponent parent, ConstrainedContext context) {
|
||||
for(int i = 2;i<CONSTRAINT_LENGTH;i++) {
|
||||
Target target = Target.by(i);
|
||||
if(constraints[i] == null) {
|
||||
context.addBound(target.get(owner), target.isXAxis());
|
||||
continue;
|
||||
}
|
||||
constraints[i].fetch(owner, parent, target, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,13 @@ public class Constraints {
|
||||
public static Pixels inverted(float value) { return new Pixels(value, true); }
|
||||
|
||||
@Override
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target) {
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
target.set(owner, inverted ? target.asArea().get(parent) - value : value);
|
||||
}
|
||||
@Override
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
context.addBound(inverted ? target.asArea().get(parent) - value : value, target.isXAxis());
|
||||
}
|
||||
}
|
||||
|
||||
public static record Parent(float padding, boolean inv) implements ISimpleConstraint {
|
||||
@ -27,10 +31,16 @@ public class Constraints {
|
||||
public static Parent inverted(float padding) { return new Parent(padding, true); }
|
||||
|
||||
@Override
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target) {
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
if(inv) target.set(owner, target.isPosition() ? target.asArea().get(parent) - padding : padding * 2);
|
||||
else target.set(owner, target.isPosition() ? padding : target.get(parent) - padding * 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
if(inv) context.addBound(target.isPosition() ? target.asArea().get(parent) - padding : padding * 2, target.isXAxis());
|
||||
else context.addBound(target.isPosition() ? padding : target.get(parent) - padding * 2, target.isXAxis());
|
||||
}
|
||||
}
|
||||
|
||||
public static record Children(float padding, boolean includeChildOffsets) implements ISimpleConstraint {
|
||||
@ -41,17 +51,27 @@ public class Constraints {
|
||||
public static Children withPos(float padding) { return new Children(padding, true); }
|
||||
|
||||
@Override
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target) {
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
if(target.isPosition()) return;
|
||||
float value = 0F;
|
||||
List<IGuiBox> children = owner.children();
|
||||
for(int i = 0,m=children.size();i<m;i++) {
|
||||
IGuiBox child = children.get(i);
|
||||
//TODO Fix this. Shouldn't this be width + offset instead of offset + width?
|
||||
value = Math.max(value, child.getBaseX() + (includeChildOffsets() ? child.getBaseWidth() : 0));
|
||||
value = Math.max(value, child.getBaseWidth() + (includeChildOffsets() ? child.getBaseX() : 0));
|
||||
}
|
||||
target.set(owner, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
float value = 0F;
|
||||
List<IGuiBox> children = owner.children();
|
||||
for(int i = 0,m=children.size();i<m;i++) {
|
||||
IGuiBox child = children.get(i);
|
||||
value = Math.max(value, child.getBaseWidth() + (includeChildOffsets() ? child.getBaseX() : 0));
|
||||
}
|
||||
context.addBound(value, target.isXAxis());
|
||||
}
|
||||
}
|
||||
|
||||
public static record Relative(float value, float padding) implements ISimpleConstraint {
|
||||
@ -60,9 +80,30 @@ public class Constraints {
|
||||
public static Relative of(float value, float padding) { return new Relative(value, padding); }
|
||||
|
||||
@Override
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target) {
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
target.set(owner, value * (target.asArea().get(parent) - padding));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
context.addBound(value * (target.asArea().get(parent) - padding), target.isXAxis());
|
||||
}
|
||||
}
|
||||
|
||||
public static record Weighted(float weight) implements ISimpleConstraint {
|
||||
public static Weighted of(float weight) { return new Weighted(weight); }
|
||||
|
||||
@Override
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
target.set(owner, target.get(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
if(target.isPosition()) return;
|
||||
context.addWeight(weight, target.isXAxis());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static record Center() implements ISimpleConstraint {
|
||||
@ -71,18 +112,29 @@ public class Constraints {
|
||||
public static Center of() { return INSTANCE; }
|
||||
|
||||
@Override
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target) {
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
Target bounds = target.asArea();
|
||||
target.set(owner, (bounds.get(parent) * 0.5F) - (bounds.get(owner) * 0.5F));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context) {
|
||||
context.addBound(target.get(owner), target.isXAxis());
|
||||
}
|
||||
}
|
||||
|
||||
public static record Conditional(BooleanSupplier supplier, IConstraint onTrue, IConstraint onFalse) implements IConstraint {
|
||||
public static Conditional of(BooleanSupplier supplier, IConstraint onTrue, IConstraint onFalse) { return new Conditional(supplier, onTrue, onFalse); }
|
||||
|
||||
@Override
|
||||
public void apply(GuiComponent owner, GuiComponent parent, Target target) {
|
||||
(supplier.getAsBoolean() ? onTrue : onFalse).apply(owner, parent, target);
|
||||
public void apply(GuiComponent owner, GuiComponent parent, Target target, ConstrainedContext context) {
|
||||
(supplier.getAsBoolean() ? onTrue : onFalse).apply(owner, parent, target, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(GuiComponent owner, GuiComponent parent, Target target, ConstrainedContext context) {
|
||||
(supplier.getAsBoolean() ? onTrue : onFalse).fetch(owner, parent, target, context);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,12 @@ import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Condi
|
||||
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Parent;
|
||||
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Pixels;
|
||||
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Relative;
|
||||
import speiger.src.coreengine.rendering.gui.layout.constraints.Constraints.Weighted;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
|
||||
|
||||
public interface IConstraint {
|
||||
public void apply(GuiComponent owner, GuiComponent child, Target target);
|
||||
public void apply(GuiComponent owner, GuiComponent parent, Target target, ConstrainedContext context);
|
||||
public void fetch(GuiComponent owner, GuiComponent parent, Target target, ConstrainedContext context);
|
||||
|
||||
public static IConstraint pixels(float value) { return Pixels.of(value); }
|
||||
public static IConstraint pixelsInv(float value) { return Pixels.inverted(value); }
|
||||
@ -30,13 +32,19 @@ public interface IConstraint {
|
||||
public static IConstraint relative(float value) { return Relative.of(value); }
|
||||
public static IConstraint relative(float value, float padding) { return Relative.of(value, padding); }
|
||||
|
||||
public static IConstraint weighted(float weight) { return Weighted.of(weight); }
|
||||
|
||||
public static IConstraint center() { return Center.of(); }
|
||||
public static IConstraint conditional(BooleanSupplier supplier, IConstraint onTrue, IConstraint onFalse) { return Conditional.of(supplier, onTrue, onFalse); }
|
||||
|
||||
public static interface ISimpleConstraint extends IConstraint {
|
||||
@Override
|
||||
default void apply(GuiComponent owner, GuiComponent parent, Target target) { apply(owner.getBox(), parent == null ? owner.screen().getBox() : parent.getBox(), target); }
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target);
|
||||
default void apply(GuiComponent owner, GuiComponent parent, Target target, ConstrainedContext context) { apply(owner.getBox(), parent == null ? owner.screen().getBox() : parent.getBox(), target, context); }
|
||||
public void apply(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context);
|
||||
|
||||
@Override
|
||||
default void fetch(GuiComponent owner, GuiComponent parent, Target target, ConstrainedContext context) { fetch(owner.getBox(), parent == null ? owner.screen().getBox() : parent.getBox(), target, context); }
|
||||
public void fetch(IGuiBox owner, IGuiBox parent, Target target, ConstrainedContext context);
|
||||
}
|
||||
|
||||
public static enum Target {
|
||||
@ -51,6 +59,7 @@ public interface IConstraint {
|
||||
public static Target pos(boolean x) { return x ? X : Y; }
|
||||
public static Target bounds(boolean x) { return x ? WIDTH : HEIGHT; }
|
||||
public boolean isPosition() { return this == X || this == Y; }
|
||||
public boolean isXAxis() { return this == X || this == WIDTH; }
|
||||
public Target asArea() {
|
||||
return switch(this) {
|
||||
case X -> WIDTH;
|
||||
@ -61,6 +70,7 @@ public interface IConstraint {
|
||||
|
||||
public float get(GuiComponent comp) { return get(comp.getBox()); }
|
||||
public void set(GuiComponent comp, float value) { set(comp.getBox(), value); }
|
||||
public float get(ConstrainedContext context) { return (isPosition() ? context.getOffset(isXAxis()) : context.get(isXAxis())); }
|
||||
|
||||
public float get(IGuiBox box) {
|
||||
return switch(this) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user