Ported GUI improvements from opfromthestart/Progressia
These changes were originally implemented by opfromthestart. OLEGSHA then patched a whole bunch of stuff - Components can now be disabled - Added BasicButton - Added Button, Checkbox and RadioButton (with RadioButtonGroup) - Added some new colors to Colors - Pressing Esc in game pops up a menu (WIP) - Fixed text z-ordering - Fixed LayoutGrid Y-direction
This commit is contained in:
parent
531a8c99c3
commit
737b495fc4
@ -34,7 +34,13 @@ public class Colors {
|
||||
DEBUG_BLUE = toVector(0xFF0000FF),
|
||||
DEBUG_CYAN = toVector(0xFF00FFFF),
|
||||
DEBUG_MAGENTA = toVector(0xFFFF00FF),
|
||||
DEBUG_YELLOW = toVector(0xFFFFFF00);
|
||||
DEBUG_YELLOW = toVector(0xFFFFFF00),
|
||||
|
||||
LIGHT_GRAY = toVector(0xFFCBCBD0),
|
||||
BLUE = toVector(0xFF37A2E6),
|
||||
HOVER_BLUE = toVector(0xFFC3E4F7),
|
||||
DISABLED_GRAY = toVector(0xFFE5E5E5),
|
||||
DISABLED_BLUE = toVector(0xFFB2D8ED);
|
||||
|
||||
public static Vec4 toVector(int argb) {
|
||||
return toVector(argb, new Vec4());
|
||||
|
@ -189,13 +189,10 @@ public class RenderTarget {
|
||||
|
||||
public void addCustomRenderer(Renderable renderable) {
|
||||
assembleCurrentClipFromFaces();
|
||||
assembled.add(
|
||||
new Clip(
|
||||
maskStack,
|
||||
getTransform(),
|
||||
renderable
|
||||
)
|
||||
);
|
||||
|
||||
float depth = this.depth--;
|
||||
Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform());
|
||||
assembled.add(new Clip(maskStack, transform, renderable));
|
||||
}
|
||||
|
||||
protected void addFaceToCurrentClip(Face face) {
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ButtonEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
|
||||
public abstract class BasicButton extends Component {
|
||||
|
||||
private final Label label;
|
||||
|
||||
private boolean isPressed = false;
|
||||
private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>());
|
||||
|
||||
public BasicButton(String name, String label, Font labelFont) {
|
||||
super(name);
|
||||
this.label = new Label(name + ".Label", labelFont, label);
|
||||
|
||||
setLayout(new LayoutAlign(10));
|
||||
addChild(this.label);
|
||||
|
||||
setFocusable(true);
|
||||
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
||||
|
||||
// Click triggers
|
||||
addListener(KeyEvent.class, e -> {
|
||||
if (e.isRepeat()) {
|
||||
return false;
|
||||
} else if (
|
||||
e.isLeftMouseButton() ||
|
||||
e.getKey() == GLFW.GLFW_KEY_SPACE ||
|
||||
e.getKey() == GLFW.GLFW_KEY_ENTER
|
||||
) {
|
||||
setPressed(e.isPress());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
addListener(new Object() {
|
||||
|
||||
// Release when losing focus
|
||||
@Subscribe
|
||||
public void onFocusChange(FocusEvent e) {
|
||||
if (!e.getNewState()) {
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Release when hover ends
|
||||
@Subscribe
|
||||
public void onHoverEnded(HoverEvent e) {
|
||||
if (!e.isNowHovered()) {
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Release when disabled
|
||||
@Subscribe
|
||||
public void onDisabled(EnableEvent e) {
|
||||
if (!e.getComponent().isEnabled()) {
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger virtualClick when button is released
|
||||
@Subscribe
|
||||
public void onRelease(ButtonEvent.Release e) {
|
||||
virtualClick();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public BasicButton(String name, String label) {
|
||||
this(name, label, new Font());
|
||||
}
|
||||
|
||||
public boolean isPressed() {
|
||||
return isPressed;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
setPressed(true);
|
||||
setPressed(false);
|
||||
}
|
||||
|
||||
public void setPressed(boolean isPressed) {
|
||||
if (this.isPressed != isPressed) {
|
||||
this.isPressed = isPressed;
|
||||
|
||||
if (isPressed) {
|
||||
takeFocus();
|
||||
}
|
||||
|
||||
dispatchEvent(ButtonEvent.create(this, this.isPressed));
|
||||
}
|
||||
}
|
||||
|
||||
public BasicButton addAction(Consumer<BasicButton> action) {
|
||||
this.actions.add(Objects.requireNonNull(action, "action"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean removeAction(Consumer<BasicButton> action) {
|
||||
return this.actions.remove(action);
|
||||
}
|
||||
|
||||
public void virtualClick() {
|
||||
this.actions.forEach(action -> {
|
||||
action.accept(this);
|
||||
});
|
||||
}
|
||||
|
||||
public Label getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
|
||||
public class Button extends BasicButton {
|
||||
|
||||
public Button(String name, String label, Font labelFont) {
|
||||
super(name, label, labelFont);
|
||||
}
|
||||
|
||||
public Button(String name, String label) {
|
||||
this(name, label, new Font());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (isPressed() || isHovered() || isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
}
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), borderColor);
|
||||
|
||||
// Inside area
|
||||
|
||||
if (isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (isHovered() && isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor);
|
||||
}
|
||||
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
|
||||
|
||||
public class Checkbox extends BasicButton {
|
||||
|
||||
private class Tick extends Component {
|
||||
|
||||
public Tick() {
|
||||
super(Checkbox.this.getName() + ".Tick");
|
||||
|
||||
setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
|
||||
int size = getPreferredSize().x;
|
||||
int x = getX();
|
||||
int y = getY() + (getHeight() - size) / 2;
|
||||
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
}
|
||||
target.fill(x, y, size, size, borderColor);
|
||||
|
||||
// Inside area
|
||||
|
||||
if (Checkbox.this.isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (Checkbox.this.isHovered() && Checkbox.this.isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor);
|
||||
}
|
||||
|
||||
// "Tick"
|
||||
|
||||
if (Checkbox.this.isChecked()) {
|
||||
target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean checked;
|
||||
|
||||
public Checkbox(String name, String label, Font labelFont, boolean check) {
|
||||
super(name, label, labelFont);
|
||||
this.checked = check;
|
||||
|
||||
assert getChildren().size() == 1 : "Checkbox expects that BasicButton contains exactly one child";
|
||||
Component basicChild = getChild(0);
|
||||
|
||||
Panel panel = new Panel(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10));
|
||||
removeChild(basicChild);
|
||||
setLayout(new LayoutAlign(0, 0.5f, 10));
|
||||
panel.setLayoutHint(basicChild.getLayoutHint());
|
||||
panel.addChild(new Tick());
|
||||
panel.addChild(basicChild);
|
||||
addChild(panel);
|
||||
|
||||
addAction(b -> switchState());
|
||||
}
|
||||
|
||||
public Checkbox(String name, String label, Font labelFont) {
|
||||
this(name, label, labelFont, false);
|
||||
}
|
||||
|
||||
public Checkbox(String name, String label, boolean check) {
|
||||
this(name, label, new Font(), check);
|
||||
}
|
||||
|
||||
public Checkbox(String name, String label) {
|
||||
this(name, label, false);
|
||||
}
|
||||
|
||||
public void switchState() {
|
||||
setChecked(!isChecked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the checked
|
||||
*/
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checked the checked to set
|
||||
*/
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -19,18 +19,23 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent;
|
||||
@ -61,6 +66,8 @@ public class Component extends Named {
|
||||
|
||||
private Object layoutHint = null;
|
||||
private Layout layout = null;
|
||||
|
||||
private boolean isEnabled = true;
|
||||
|
||||
private boolean isFocusable = false;
|
||||
private boolean isFocused = false;
|
||||
@ -285,9 +292,30 @@ public class Component extends Named {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this component is focusable. A component needs to be
|
||||
* focusable to become focused. A component that is focusable may not
|
||||
* necessarily be ready to gain focus (see {@link #canGainFocusNow()}).
|
||||
*
|
||||
* @return {@code true} iff the component is focusable
|
||||
* @see #canGainFocusNow()
|
||||
*/
|
||||
public boolean isFocusable() {
|
||||
return isFocusable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this component can become focused at this moment.
|
||||
* <p>
|
||||
* The implementation of this method in {@link Component} considers the
|
||||
* component a focus candidate if it is both focusable and enabled.
|
||||
*
|
||||
* @return {@code true} iff the component can receive focus
|
||||
* @see #isFocusable()
|
||||
*/
|
||||
public boolean canGainFocusNow() {
|
||||
return isFocusable() && isEnabled();
|
||||
}
|
||||
|
||||
public Component setFocusable(boolean focusable) {
|
||||
this.isFocusable = focusable;
|
||||
@ -337,7 +365,7 @@ public class Component extends Named {
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.isFocusable()) {
|
||||
if (component.canGainFocusNow()) {
|
||||
setFocused(false);
|
||||
component.setFocused(true);
|
||||
return;
|
||||
@ -379,7 +407,7 @@ public class Component extends Named {
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.isFocusable()) {
|
||||
if (component.canGainFocusNow()) {
|
||||
setFocused(false);
|
||||
component.setFocused(true);
|
||||
return;
|
||||
@ -432,13 +460,52 @@ public class Component extends Named {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables this component. An {@link EnableEvent} is dispatched
|
||||
* if the state changes.
|
||||
*
|
||||
* @param enabled {@code true} to enable the component, {@code false} to
|
||||
* disable the component
|
||||
* @see #setEnabledRecursively(boolean)
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (this.isEnabled != enabled) {
|
||||
if (isFocused() && isEnabled()) {
|
||||
focusNext();
|
||||
}
|
||||
|
||||
if (isEnabled()) {
|
||||
setHovered(false);
|
||||
}
|
||||
|
||||
this.isEnabled = enabled;
|
||||
dispatchEvent(new EnableEvent(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables this component and all of its children recursively.
|
||||
*
|
||||
* @param enabled {@code true} to enable the components, {@code false} to
|
||||
* disable the components
|
||||
* @see #setEnabled(boolean)
|
||||
*/
|
||||
public void setEnabledRecursively(boolean enabled) {
|
||||
setEnabled(enabled);
|
||||
getChildren().forEach(c -> c.setEnabledRecursively(enabled));
|
||||
}
|
||||
|
||||
public boolean isHovered() {
|
||||
return isHovered;
|
||||
}
|
||||
|
||||
protected void setHovered(boolean isHovered) {
|
||||
if (this.isHovered != isHovered) {
|
||||
if (this.isHovered != isHovered && isEnabled()) {
|
||||
this.isHovered = isHovered;
|
||||
|
||||
if (!isHovered && !getChildren().isEmpty()) {
|
||||
@ -502,7 +569,7 @@ public class Component extends Named {
|
||||
}
|
||||
|
||||
protected void handleInput(Input input) {
|
||||
if (inputBus != null) {
|
||||
if (inputBus != null && isEnabled()) {
|
||||
inputBus.dispatch(input);
|
||||
}
|
||||
}
|
||||
@ -598,6 +665,17 @@ public class Component extends Named {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the reassembly to occur.
|
||||
* <p>
|
||||
* This method is invoked in root components whenever a
|
||||
* {@linkplain #requestReassembly() reassembly request} is made by one of
|
||||
* its children. When creating the dedicated root component, override this
|
||||
* method to perform any implementation-specific actions that will cause a
|
||||
* reassembly as soon as possible.
|
||||
* <p>
|
||||
* The default implementation of this method does nothing.
|
||||
*/
|
||||
protected void handleReassemblyRequest() {
|
||||
// To be overridden
|
||||
}
|
||||
@ -637,6 +715,135 @@ public class Component extends Named {
|
||||
protected void assembleChildren(RenderTarget target) {
|
||||
getChildren().forEach(child -> child.assemble(target));
|
||||
}
|
||||
|
||||
/*
|
||||
* Automatic Reassembly
|
||||
*/
|
||||
|
||||
/**
|
||||
* The various kinds of changes that may be used with
|
||||
* {@link Component#reassembleAt(ARTrigger...)}.
|
||||
*/
|
||||
protected static enum ARTrigger {
|
||||
/**
|
||||
* Reassemble the component whenever its hover status changes, e.g.
|
||||
* whenever the pointer enters or leaves its bounds.
|
||||
*/
|
||||
HOVER,
|
||||
|
||||
/**
|
||||
* Reassemble the component whenever it gains or loses focus.
|
||||
* <p>
|
||||
* <em>Component must be focusable to be able to gain focus.</em> The
|
||||
* component will not be reassembled unless
|
||||
* {@link Component#setFocusable(boolean) setFocusable(true)} has been
|
||||
* invoked.
|
||||
*/
|
||||
FOCUS,
|
||||
|
||||
/**
|
||||
* Reassemble the component whenever it is enabled or disabled.
|
||||
*/
|
||||
ENABLE
|
||||
}
|
||||
|
||||
/**
|
||||
* All trigger objects (event listeners) that are currently registered with
|
||||
* {@link #eventBus}. The field is {@code null} until the first trigger is
|
||||
* installed.
|
||||
*/
|
||||
private Map<ARTrigger, Object> autoReassemblyTriggerObjects = null;
|
||||
|
||||
private Object createTriggerObject(ARTrigger type) {
|
||||
switch (type) {
|
||||
case HOVER:
|
||||
return new Object() {
|
||||
@Subscribe
|
||||
public void onHoverChanged(HoverEvent e) {
|
||||
requestReassembly();
|
||||
}
|
||||
};
|
||||
case FOCUS:
|
||||
return new Object() {
|
||||
@Subscribe
|
||||
public void onFocusChanged(FocusEvent e) {
|
||||
requestReassembly();
|
||||
}
|
||||
};
|
||||
case ENABLE:
|
||||
return new Object() {
|
||||
@Subscribe
|
||||
public void onEnabled(EnableEvent e) {
|
||||
requestReassembly();
|
||||
}
|
||||
};
|
||||
default:
|
||||
throw new NullPointerException("type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that {@link #requestReassembly()} is invoked on this component
|
||||
* whenever any of the specified changes occur. Duplicate attempts to
|
||||
* register the same trigger are silently ignored.
|
||||
* <p>
|
||||
* {@code triggers} may be empty, which results in a no-op. It must not be
|
||||
* {@code null}.
|
||||
*
|
||||
* @param triggers the {@linkplain ARTrigger triggers} to
|
||||
* request reassembly with.
|
||||
* @see #disableAutoReassemblyAt(ARTrigger...)
|
||||
*/
|
||||
protected synchronized void reassembleAt(ARTrigger... triggers) {
|
||||
|
||||
Objects.requireNonNull(triggers, "triggers");
|
||||
if (triggers.length == 0)
|
||||
return;
|
||||
|
||||
if (autoReassemblyTriggerObjects == null) {
|
||||
autoReassemblyTriggerObjects = new EnumMap<>(ARTrigger.class);
|
||||
}
|
||||
|
||||
for (ARTrigger trigger : triggers) {
|
||||
if (!autoReassemblyTriggerObjects.containsKey(trigger)) {
|
||||
Object triggerObject = createTriggerObject(trigger);
|
||||
addListener(trigger);
|
||||
autoReassemblyTriggerObjects.put(trigger, triggerObject);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that {@link #requestReassembly()} is no longer invoked on this
|
||||
* component whenever any of the specified changes occur. After a trigger is
|
||||
* removed, it may be reinstalled with
|
||||
* {@link #reassembleAt(ARTrigger...)}. Attempts to remove a
|
||||
* nonexistant trigger are silently ignored.
|
||||
* <p>
|
||||
* {@code triggers} may be empty, which results in a no-op. It must not be
|
||||
* {@code null}.
|
||||
*
|
||||
* @param triggers the {@linkplain ARTrigger triggers} to remove
|
||||
* @see #reassemblyAt(ARTrigger...)
|
||||
*/
|
||||
protected synchronized void disableAutoReassemblyAt(ARTrigger... triggers) {
|
||||
|
||||
Objects.requireNonNull(triggers, "triggers");
|
||||
if (triggers.length == 0)
|
||||
return;
|
||||
|
||||
if (autoReassemblyTriggerObjects == null)
|
||||
return;
|
||||
|
||||
for (ARTrigger trigger : triggers) {
|
||||
Object triggerObject = autoReassemblyTriggerObjects.remove(trigger);
|
||||
if (triggerObject != null) {
|
||||
removeListener(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns a component that displays this component in its center.
|
||||
|
@ -82,6 +82,11 @@ public class Label extends Component {
|
||||
public Font getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
requestReassembly();
|
||||
}
|
||||
|
||||
public String getCurrentText() {
|
||||
return currentText;
|
||||
@ -96,11 +101,7 @@ public class Label extends Component {
|
||||
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
||||
|
||||
target.pushTransform(
|
||||
new Mat4().identity().translate(startX, getY(), -1000) // TODO wtf
|
||||
// is this
|
||||
// magic
|
||||
// <---
|
||||
.scale(2)
|
||||
new Mat4().identity().translate(startX, getY(), 0).scale(2)
|
||||
);
|
||||
|
||||
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
||||
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
|
||||
public class RadioButton extends BasicButton {
|
||||
|
||||
private class Tick extends Component {
|
||||
|
||||
public Tick() {
|
||||
super(RadioButton.this.getName() + ".Tick");
|
||||
|
||||
setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2));
|
||||
}
|
||||
|
||||
private void cross(RenderTarget target, int x, int y, int size, Vec4 color) {
|
||||
target.fill(x + 4, y, size - 8, size, color);
|
||||
target.fill(x + 2, y + 2, size - 4, size - 4, color);
|
||||
target.fill(x, y + 4, size, size - 8, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
|
||||
int size = getPreferredSize().x;
|
||||
int x = getX();
|
||||
int y = getY() + (getHeight() - size) / 2;
|
||||
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
}
|
||||
cross(target, x, y, size, borderColor);
|
||||
|
||||
// Inside area
|
||||
|
||||
if (RadioButton.this.isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (RadioButton.this.isHovered() && RadioButton.this.isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
cross(target, x + 2, y + 2, size - 4, backgroundColor);
|
||||
}
|
||||
|
||||
// "Tick"
|
||||
|
||||
if (RadioButton.this.isChecked()) {
|
||||
cross(target, x + 4, y + 4, size - 8, Colors.BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean checked;
|
||||
|
||||
private RadioButtonGroup group = null;
|
||||
|
||||
public RadioButton(String name, String label, Font labelFont, boolean check) {
|
||||
super(name, label, labelFont);
|
||||
this.checked = check;
|
||||
|
||||
assert getChildren().size() == 1 : "RadioButton expects that BasicButton contains exactly one child";
|
||||
Component basicChild = getChild(0);
|
||||
|
||||
Panel panel = new Panel(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10));
|
||||
removeChild(basicChild);
|
||||
setLayout(new LayoutAlign(0, 0.5f, 10));
|
||||
panel.setLayoutHint(basicChild.getLayoutHint());
|
||||
panel.addChild(new Tick());
|
||||
panel.addChild(basicChild);
|
||||
addChild(panel);
|
||||
|
||||
addListener(KeyEvent.class, e -> {
|
||||
if (e.isRelease()) return false;
|
||||
|
||||
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
|
||||
if (group != null) {
|
||||
group.selectPrevious();
|
||||
group.getSelected().takeFocus();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) {
|
||||
if (group != null) {
|
||||
group.selectNext();
|
||||
group.getSelected().takeFocus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
addAction(b -> setChecked(true));
|
||||
}
|
||||
|
||||
public RadioButton(String name, String label, Font labelFont) {
|
||||
this(name, label, labelFont, false);
|
||||
}
|
||||
|
||||
public RadioButton(String name, String label, boolean check) {
|
||||
this(name, label, new Font(), check);
|
||||
}
|
||||
|
||||
public RadioButton(String name, String label) {
|
||||
this(name, label, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param group the group to set
|
||||
*/
|
||||
public RadioButton setGroup(RadioButtonGroup group) {
|
||||
|
||||
if (this.group != null) {
|
||||
group.selectNext();
|
||||
removeAction(group.listener);
|
||||
group.buttons.remove(this);
|
||||
group.getSelected(); // Clear reference if this was the only button in the group
|
||||
}
|
||||
|
||||
this.group = group;
|
||||
|
||||
if (this.group != null) {
|
||||
group.buttons.add(this);
|
||||
addAction(group.listener);
|
||||
}
|
||||
|
||||
setChecked(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the checked
|
||||
*/
|
||||
public boolean isChecked() {
|
||||
return checked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param checked the checked to set
|
||||
*/
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
|
||||
if (group != null) {
|
||||
group.listener.accept(this); // Failsafe for manual invocations of setChecked()
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class RadioButtonGroup {
|
||||
|
||||
private final Collection<Consumer<RadioButtonGroup>> actions = Collections.synchronizedCollection(new ArrayList<>());
|
||||
final List<RadioButton> buttons = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private RadioButton selected = null;
|
||||
|
||||
Consumer<BasicButton> listener = b -> {
|
||||
if (b instanceof RadioButton && ((RadioButton) b).isChecked() && buttons.contains(b)) {
|
||||
select((RadioButton) b);
|
||||
}
|
||||
};
|
||||
|
||||
public RadioButtonGroup addAction(Consumer<RadioButtonGroup> action) {
|
||||
this.actions.add(Objects.requireNonNull(action, "action"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean removeAction(Consumer<BasicButton> action) {
|
||||
return this.actions.remove(action);
|
||||
}
|
||||
|
||||
public List<RadioButton> getButtons() {
|
||||
return Collections.unmodifiableList(buttons);
|
||||
}
|
||||
|
||||
public synchronized RadioButton getSelected() {
|
||||
if (!buttons.contains(selected)) {
|
||||
selected = null;
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
public synchronized void select(RadioButton button) {
|
||||
if (button != null && !buttons.contains(button)) {
|
||||
throw new IllegalArgumentException("Button " + button + " is not in the group");
|
||||
}
|
||||
|
||||
getSelected(); // Clear if invalid
|
||||
|
||||
if (selected == button) {
|
||||
return; // Terminate listener-setter recursion
|
||||
}
|
||||
|
||||
if (selected != null) {
|
||||
selected.setChecked(false);
|
||||
}
|
||||
|
||||
selected = button;
|
||||
|
||||
if (selected != null) {
|
||||
selected.setChecked(true);
|
||||
}
|
||||
|
||||
actions.forEach(action -> action.accept(this));
|
||||
}
|
||||
|
||||
public void selectNext() {
|
||||
selectNeighbour(+1);
|
||||
}
|
||||
|
||||
public void selectPrevious() {
|
||||
selectNeighbour(-1);
|
||||
}
|
||||
|
||||
private synchronized void selectNeighbour(int direction) {
|
||||
if (getSelected() == null) {
|
||||
if (buttons.isEmpty()) {
|
||||
throw new IllegalStateException("Cannot select neighbour button: group empty");
|
||||
}
|
||||
|
||||
select(buttons.get(0));
|
||||
} else {
|
||||
RadioButton button;
|
||||
int index = buttons.indexOf(selected);
|
||||
|
||||
do {
|
||||
index += direction;
|
||||
|
||||
if (index >= buttons.size()) {
|
||||
index = 0;
|
||||
} else if (index < 0) {
|
||||
index = buttons.size() - 1;
|
||||
}
|
||||
|
||||
button = buttons.get(index);
|
||||
} while (button != getSelected() && !button.isEnabled());
|
||||
|
||||
select(button);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
|
||||
|
||||
public class ButtonEvent extends ComponentEvent {
|
||||
|
||||
public static class Press extends ButtonEvent {
|
||||
public Press(BasicButton button) {
|
||||
super(button, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Release extends ButtonEvent {
|
||||
public Release(BasicButton button) {
|
||||
super(button, false);
|
||||
}
|
||||
}
|
||||
|
||||
private final boolean isPress;
|
||||
|
||||
protected ButtonEvent(BasicButton button, boolean isPress) {
|
||||
super(button);
|
||||
this.isPress = isPress;
|
||||
}
|
||||
|
||||
public static ButtonEvent create(BasicButton button, boolean isPress) {
|
||||
if (isPress) {
|
||||
return new Press(button);
|
||||
} else {
|
||||
return new Release(button);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPress() {
|
||||
return isPress;
|
||||
}
|
||||
|
||||
public boolean isRelease() {
|
||||
return !isPress;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
|
||||
public class EnableEvent extends ComponentEvent {
|
||||
|
||||
public EnableEvent(Component component) {
|
||||
super(component);
|
||||
}
|
||||
|
||||
}
|
@ -97,16 +97,27 @@ public class LayoutGrid implements Layout {
|
||||
void setBounds(int column, int row, Component child, Component parent) {
|
||||
if (!isSummed)
|
||||
throw new IllegalStateException("Not summed yet");
|
||||
|
||||
int width, height;
|
||||
|
||||
if (column == columns.length - 1) {
|
||||
width = parent.getWidth() - margin - columns[column];
|
||||
} else {
|
||||
width = columns[column + 1] - columns[column] - gap;
|
||||
}
|
||||
|
||||
if (row == rows.length - 1) {
|
||||
height = parent.getHeight() - margin - rows[row];
|
||||
} else {
|
||||
height = rows[row + 1] - rows[row] - gap;
|
||||
}
|
||||
|
||||
child.setBounds(
|
||||
parent.getX() + columns[column],
|
||||
parent.getY() + rows[row],
|
||||
parent.getY() + parent.getHeight() - (rows[row] + height),
|
||||
|
||||
(column != (columns.length - 1) ? (columns[column + 1] - columns[column] - gap)
|
||||
: (parent.getWidth() - margin - columns[column])),
|
||||
|
||||
(row != (rows.length - 1) ? (rows[row + 1] - rows[row] - gap)
|
||||
: (parent.getHeight() - margin - rows[row]))
|
||||
width,
|
||||
height
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -132,10 +143,9 @@ public class LayoutGrid implements Layout {
|
||||
GridDimensions grid = calculateGrid(c);
|
||||
grid.sum();
|
||||
|
||||
int[] coords;
|
||||
for (Component child : c.getChildren()) {
|
||||
coords = (int[]) child.getLayoutHint();
|
||||
grid.setBounds(coords[0], coords[1], child, c);
|
||||
Vec2i coords = (Vec2i) child.getLayoutHint();
|
||||
grid.setBounds(coords.x, coords.y, child, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,11 +159,10 @@ public class LayoutGrid implements Layout {
|
||||
|
||||
private GridDimensions calculateGrid(Component parent) {
|
||||
GridDimensions result = new GridDimensions();
|
||||
int[] coords;
|
||||
|
||||
for (Component child : parent.getChildren()) {
|
||||
coords = (int[]) child.getLayoutHint();
|
||||
result.add(coords[0], coords[1], child.getPreferredSize());
|
||||
Vec2i coords = (Vec2i) child.getLayoutHint();
|
||||
result.add(coords.x, coords.y, child.getPreferredSize());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
104
src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java
Normal file
104
src/main/java/ru/windcorp/progressia/test/LayerButtonTest.java
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Button;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Checkbox;
|
||||
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||
import ru.windcorp.progressia.client.graphics.gui.RadioButton;
|
||||
import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
||||
|
||||
public class LayerButtonTest extends GUILayer {
|
||||
|
||||
public LayerButtonTest() {
|
||||
super("LayerButtonTest", new LayoutBorderHorizontal(0));
|
||||
|
||||
Panel background = new Panel("Background", new LayoutAlign(10)) {
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
target.fill(Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
};
|
||||
|
||||
Panel panel = new Panel("Panel", new LayoutVertical(10)) {
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.LIGHT_GRAY);
|
||||
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, Colors.WHITE);
|
||||
}
|
||||
};
|
||||
|
||||
Button blockableButton;
|
||||
panel.addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> {
|
||||
System.out.println("Button Blockable!");
|
||||
}));
|
||||
blockableButton.setEnabled(false);
|
||||
|
||||
panel.addChild(new Checkbox("EnableButton", "Enable").addAction(b -> {
|
||||
blockableButton.setEnabled(((Checkbox) b).isChecked());
|
||||
}));
|
||||
|
||||
RadioButtonGroup group = new RadioButtonGroup().addAction(g -> {
|
||||
System.out.println("RBG! " + g.getSelected().getLabel().getCurrentText());
|
||||
});
|
||||
|
||||
panel.addChild(new RadioButton("RB1", "Moon").setGroup(group));
|
||||
panel.addChild(new RadioButton("RB2", "Type").setGroup(group));
|
||||
panel.addChild(new RadioButton("RB3", "Ice").setGroup(group));
|
||||
panel.addChild(new RadioButton("RB4", "Cream").setGroup(group));
|
||||
|
||||
panel.getChild(panel.getChildren().size() - 1).setEnabled(false);
|
||||
|
||||
panel.getChild(1).takeFocus();
|
||||
|
||||
background.addChild(panel);
|
||||
getRoot().addChild(background.setLayoutHint(LayoutBorderHorizontal.CENTER));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInput(Input input) {
|
||||
|
||||
if (!input.isConsumed()) {
|
||||
|
||||
InputEvent e = input.getEvent();
|
||||
|
||||
if ((e instanceof KeyEvent) && ((KeyEvent) e).isPress() && ((KeyEvent) e).getKey() == GLFW.GLFW_KEY_ESCAPE) {
|
||||
GUI.removeLayer(this);
|
||||
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
super.handleInput(input);
|
||||
input.consume();
|
||||
}
|
||||
|
||||
}
|
@ -184,6 +184,7 @@ public class TestPlayerControls {
|
||||
case GLFW.GLFW_KEY_ESCAPE:
|
||||
if (!event.isPress())
|
||||
return false;
|
||||
|
||||
handleEscape();
|
||||
break;
|
||||
|
||||
@ -293,13 +294,20 @@ public class TestPlayerControls {
|
||||
}
|
||||
|
||||
private void handleEscape() {
|
||||
if (captureMouse) {
|
||||
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
||||
} else {
|
||||
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
|
||||
}
|
||||
// if (captureMouse) {
|
||||
// GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
||||
// } else {
|
||||
// GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
|
||||
// }
|
||||
//
|
||||
// captureMouse = !captureMouse;
|
||||
|
||||
captureMouse = !captureMouse;
|
||||
movementForward = 0;
|
||||
movementRight = 0;
|
||||
movementUp = 0;
|
||||
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
||||
GUI.addTopLayer(new LayerButtonTest());
|
||||
|
||||
updateGUI();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user