Reimplement pattern panel menu

This commit is contained in:
DBotThePony 2021-08-22 16:43:19 +07:00
parent b65bbab767
commit 7bd1de8171
Signed by: DBot
GPG Key ID: DCC23B5715498507
17 changed files with 1472 additions and 689 deletions

View File

@ -5,6 +5,7 @@ import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.RegistryManager; import net.minecraftforge.registries.RegistryManager;
@ -28,6 +29,10 @@ public record PatternState(@Nonnull UUID id, @Nonnull Item item, double research
return false; return false;
} }
public ItemStack stack() {
return new ItemStack(item, 1);
}
@Override @Override
public int hashCode() { public int hashCode() {
return id.hashCode(); return id.hashCode();

View File

@ -21,18 +21,19 @@ import ru.dbotthepony.mc.otm.capability.PatternState;
import ru.dbotthepony.mc.otm.menu.MatterPanelMenu; import ru.dbotthepony.mc.otm.menu.MatterPanelMenu;
import ru.dbotthepony.mc.otm.network.MatteryNetworking; import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.network.PatternReplicationRequestPacket; import ru.dbotthepony.mc.otm.network.PatternReplicationRequestPacket;
import ru.dbotthepony.mc.otm.screen.panels.*;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.lwjgl.opengl.GL11.GL_ALWAYS; import static org.lwjgl.opengl.GL11.GL_ALWAYS;
import static org.lwjgl.opengl.GL11.GL_LESS; import static org.lwjgl.opengl.GL11.GL_LESS;
public class MatterPanelScreen extends MatteryScreen<MatterPanelMenu> { public class MatterPanelScreen extends MatteryScreen<MatterPanelMenu> {
private static final int modal_width = 213; private static final int MODAL_WIDTH = 213;
private static final int modal_height = 110; private static final int MODAL_HEIGHT = 110;
private boolean open_task_list = false;
protected static final ResourceLocation CONTAINER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/matter_panel.png"); protected static final ResourceLocation CONTAINER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/matter_panel.png");
@ -47,599 +48,362 @@ public class MatterPanelScreen extends MatteryScreen<MatterPanelMenu> {
imageHeight = 187; imageHeight = 187;
titleLabelY = 5; titleLabelY = 5;
p_97741_.networkTaskWatcher(task -> {
if (open_task != null && open_task.equals(task)) {
open_task = task;
} }
}, task -> {
if (open_task != null && open_task.equals(task)) { public static final int GRID_WIDTH = 8;
closeTask(); public static final int GRID_HEIGHT = 9;
private final ArrayList<AbstractSlotPanel> pattern_slots = new ArrayList<>();
private final ArrayList<AbstractSlotPanel> task_slots = new ArrayList<>();
@Nullable
@Override
protected FramePanel makeMainFrame() {
float width = GRID_WIDTH * AbstractSlotPanel.REGULAR_DIMENSIONS + ScrollBarPanel.WIDTH + FramePanel.PADDING * 2 + 8;
float height = GRID_HEIGHT * AbstractSlotPanel.REGULAR_DIMENSIONS + FramePanel.PADDING_TOP + FramePanel.PADDING;
var scroll_panel = new ScrollBarPanel(this, null, 0, 0, 0);
var frame = new FramePanel(this, null, 0, 0, width, height, getTitle()) {
@Override
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
return scroll_panel.mouseScrolledInner(mouse_x, mouse_y, scroll);
}
};
var patterns_tab = frame.addTab(FramePanel.FrameTabPosition.TOP, () -> {
for (var slot : pattern_slots) {
slot.setVisible(true);
}
}, () -> {
for (var slot : pattern_slots) {
slot.setVisible(false);
}
});
var tasks_tab = frame.addTab(FramePanel.FrameTabPosition.TOP, () -> {
for (var slot : task_slots) {
slot.setVisible(true);
}
}, () -> {
for (var slot : task_slots) {
slot.setVisible(false);
}
});
scroll_panel.setParent(frame);
scroll_panel.setDocking(Dock.RIGHT);
scroll_panel.setupRowMultiplier(() -> {
if (tasks_tab.isActive()) {
return menu.tasks.size() / 9;
}
return menu.patterns.size() / 9;
});
var grid = new GridPanel(this, frame, 0, 0, GRID_WIDTH * AbstractSlotPanel.REGULAR_DIMENSIONS, 0, GRID_WIDTH, GRID_HEIGHT) {
@Override
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
return scroll_panel.mouseScrolledInner(mouse_x, mouse_y, scroll);
}
};
grid.setDocking(Dock.LEFT);
grid.setDockMargin(4, 0, 0, 0);
for (int i = 0; i < GRID_WIDTH * GRID_HEIGHT; i++) {
int slot = i;
pattern_slots.add(new AbstractSlotPanel(this, grid, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
if (slot >= menu.patterns.size()) {
return ItemStack.EMPTY;
}
return menu.patterns.get(slot).stack();
}
@Override
protected List<Component> getItemStackTooltip(ItemStack stack) {
if (slot >= menu.patterns.size()) {
return List.of();
}
return getPatternTooltip(super.getItemStackTooltip(stack), menu.patterns.get(slot));
}
@Override
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
return scroll_panel.mouseScrolledInner(mouse_x, mouse_y, scroll);
}
@Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
if (slot >= menu.patterns.size()) {
return true;
}
openPattern(menu.patterns.get(slot));
return true;
}
});
task_slots.add(new AbstractSlotPanel(this, grid, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
if (slot >= menu.tasks.size()) {
return ItemStack.EMPTY;
}
var task = menu.tasks.get(slot);
return task.stack(Math.max(task.required(), 1));
}
@Override
protected List<Component> getItemStackTooltip(ItemStack stack) {
if (slot >= menu.tasks.size()) {
return List.of();
}
return getTaskTooltip(super.getItemStackTooltip(stack), menu.tasks.get(slot));
}
@Override
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
return scroll_panel.mouseScrolledInner(mouse_x, mouse_y, scroll);
}
@Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
if (slot >= menu.tasks.size()) {
return true;
}
openTask(menu.tasks.get(slot));
return true;
} }
}); });
} }
private PatternState open_pattern; for (var slot : task_slots) {
private MatterTask open_task; slot.setVisible(false);
private EditBox input_amount;
private Button inc_8;
private Button inc_64;
private Button inc_256;
private Button dec_8;
private Button dec_64;
private Button dec_256;
private Button send_modal;
private Button cancel_modal;
private Button cancel_task;
private Button close_task;
private PatternState hovered_pattern;
private MatterTask hovered_task;
private double scroller_position = 0;
@Override
protected void init() {
super.init();
int x = (width - modal_width) / 2;
int y = (height - modal_height) / 2;
// окно на создание запроса
int top_level = 15;
int button_width = 40;
int right = 5 + button_width;
int box_width = modal_width - 5 - 5 - 30;
inc_8 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 8), (btn) -> onChangeAmountPress(8));
right += 2 + button_width;
inc_64 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 64), (btn) -> onChangeAmountPress(64));
right += 2 + button_width;
inc_256 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 256), (btn) -> onChangeAmountPress(256));
right = 5 + button_width;
top_level += 24;
input_amount = new EditBox(font, x + modal_width - 5 - box_width, y + top_level, box_width, 16, new TranslatableComponent("otm.container.matter_panel.number_input"));
input_amount.setMaxLength(6);
input_amount.setValue("1");
input_amount.visible = false;
top_level += 20;
dec_8 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 8), (btn) -> onChangeAmountPress(-8));
right += 2 + button_width;
dec_64 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 64), (btn) -> onChangeAmountPress(-64));
right += 2 + button_width;
dec_256 = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 256), (btn) -> onChangeAmountPress(-256));
top_level += 24;
right = 5 + button_width;
cancel_modal = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.cancel"), (btn) -> closePattern());
right += 2 + button_width;
send_modal = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.send"), (btn) -> onSend());
inc_8.visible = false;
inc_64.visible = false;
inc_256.visible = false;
dec_8.visible = false;
dec_64.visible = false;
dec_256.visible = false;
send_modal.visible = false;
cancel_modal.visible = false;
addWidget(input_amount);
addWidget(inc_8);
addWidget(inc_64);
addWidget(inc_256);
addWidget(dec_8);
addWidget(dec_64);
addWidget(dec_256);
addWidget(send_modal);
addWidget(cancel_modal);
// окно на отмену запроса
right = 5 + button_width;
top_level = modal_height - 8 - 20;
close_task = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.close"), (btn) -> closeTask());
button_width = 90;
right += 2 + button_width;
cancel_task = new Button(x + modal_width - right, y + top_level, button_width, 20, new TranslatableComponent("otm.container.matter_panel.cancel_task"), (btn) -> cancelTask());
close_task.visible = false;
cancel_task.visible = false;
addWidget(close_task);
addWidget(cancel_task);
} }
private void onChangeAmountPress(int amount) { return frame;
}
private List<Component> getTaskTooltip(List<Component> input, MatterTask task) {
input.add(new TranslatableComponent("otm.gui.matter_task.total", task.total()).withStyle(ChatFormatting.GRAY));
input.add(new TranslatableComponent("otm.gui.matter_task.required", task.required()).withStyle(ChatFormatting.GRAY));
input.add(new TranslatableComponent("otm.gui.matter_task.in_progress", task.in_progress()).withStyle(ChatFormatting.GRAY));
input.add(new TranslatableComponent("otm.gui.matter_task.finished", task.finished()).withStyle(ChatFormatting.GRAY));
return input;
}
private List<Component> getPatternTooltip(List<Component> input, PatternState pattern) {
input.add(new TranslatableComponent("otm.item.pattern.research", String.format("%.2f", pattern.research_percent() * 100d)).withStyle(ChatFormatting.AQUA));
return input;
}
private void openTask(MatterTask task) {
var task_frame = new FramePanel(this, null, 0, 0, MODAL_WIDTH, MODAL_HEIGHT, new TranslatableComponent("otm.container.matter_panel.task")) {
@Override
public void tick() {
super.tick();
if (!menu.tasks.contains(task)) {
remove();
}
}
};
var row_1 = new EditablePanel(this, task_frame);
var row_2 = new EditablePanel(this, task_frame);
row_1.setHeight(18);
row_2.setHeight(20);
row_1.setDocking(Dock.TOP);
row_2.setDocking(Dock.TOP);
row_1.setDockMargin(0, 2, 0, 0);
row_2.setDockMargin(0, 2, 0, 0);
var slot = new AbstractSlotPanel(this, row_1, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
var task1_index = menu.tasks.indexOf(task);
if (task1_index != -1) {
var task1 = menu.tasks.get(task1_index);
return task1.stack(Math.max(task1.required(), 1));
}
return ItemStack.EMPTY;
}
@Override
protected List<Component> getItemStackTooltip(ItemStack stack) {
var task1_index = menu.tasks.indexOf(task);
List<Component> get_list = super.getItemStackTooltip(stack);
if (task1_index != -1) {
getTaskTooltip(get_list, menu.tasks.get(task1_index));
}
return get_list;
}
};
slot.setDocking(Dock.LEFT);
var button = new ButtonPanel(this, row_2, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.close"));
button.setDocking(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button.bindOnPress(task_frame::remove);
button = new ButtonPanel(this, row_2, 0, 0, 80, 20, new TranslatableComponent("otm.container.matter_panel.cancel_task"));
button.setDocking(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button.bindOnPress(() -> {
menu.requestTaskCancel(task.id());
task_frame.remove();
});
task_frame.toScreenCenter();
addPanel(task_frame);
}
private void openPattern(PatternState state) {
var pattern_frame = new FramePanel(this, null, 0, 0, MODAL_WIDTH, MODAL_HEIGHT, new TranslatableComponent("otm.container.matter_panel.label"));
var row_1 = new EditablePanel(this, pattern_frame);
var row_2 = new EditablePanel(this, pattern_frame);
var row_3 = new EditablePanel(this, pattern_frame);
var row_4 = new EditablePanel(this, pattern_frame);
row_1.setDocking(Dock.TOP);
row_2.setDocking(Dock.TOP);
row_3.setDocking(Dock.TOP);
row_4.setDocking(Dock.TOP);
row_1.setHeight(20);
row_2.setHeight(20);
row_3.setHeight(20);
row_4.setHeight(20);
row_1.setDockMargin(0, 2, 0, 0);
row_2.setDockMargin(0, 2, 0, 0);
row_3.setDockMargin(0, 2, 0, 0);
row_4.setDockMargin(0, 2, 0, 0);
var slot = new AbstractSlotPanel(this, row_2, 0, 0) {
@Nonnull
@Override
protected ItemStack getItemStack() {
return new ItemStack(state.item(), 1);
}
@Override
protected List<Component> getItemStackTooltip(ItemStack stack) {
return getPatternTooltip(super.getItemStackTooltip(stack), state);
}
};
var input_amount = new EditBoxPanel(this, row_2, 0, 0, 10, 20, new TextComponent("Input amount")) {
@Override
protected void factorize(EditBox widget, boolean recreation) {
super.factorize(widget, recreation);
widget.setMaxLength(6);
if (!recreation) {
widget.setValue("1");
}
}
private void increase(int amount) {
int value = 1; int value = 1;
try { try {
value = Integer.parseInt(input_amount.getValue()); value = Integer.parseInt(getOrCreateWidget().getValue());
} catch (Exception ignored) { } catch (Exception ignored) {
} }
if (value == 1 && amount > 0) if (value == 1 && amount > 0)
input_amount.setValue(Integer.toString(amount)); getOrCreateWidget().setValue(Integer.toString(amount));
else else
input_amount.setValue(Integer.toString(Math.max(1, Math.min(99999, value + amount)))); getOrCreateWidget().setValue(Integer.toString(Math.max(1, Math.min(99999, value + amount))));
} }
};
private void onSend() { var button = new ButtonPanel(this, row_1, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 8));
button.bindOnPress(() -> input_amount.increase(8));
button.setDocking(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_1, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 64));
button.setDocking(Dock.RIGHT);
button.bindOnPress(() -> input_amount.increase(64));
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_1, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.increase_by", 256));
button.setDocking(Dock.RIGHT);
button.bindOnPress(() -> input_amount.increase(256));
button.setDockMargin(2, 0, 0, 0);
slot.setDocking(Dock.LEFT);
slot.setDockMargin(0, 0, 4, 0);
input_amount.setDocking(Dock.FILL);
button = new ButtonPanel(this, row_3, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 8));
button.bindOnPress(() -> input_amount.increase(-8));
button.setDocking(Dock.RIGHT);
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_3, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 64));
button.setDocking(Dock.RIGHT);
button.bindOnPress(() -> input_amount.increase(-64));
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_3, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.decrease_by", 256));
button.setDocking(Dock.RIGHT);
button.bindOnPress(() -> input_amount.increase(-256));
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_4, 0, 0, 40, 20, new TranslatableComponent("otm.container.matter_panel.cancel"));
button.setDocking(Dock.RIGHT);
button.bindOnPress(pattern_frame::remove);
button.setDockMargin(2, 0, 0, 0);
button = new ButtonPanel(this, row_4, 0, 0, 82, 20, new TranslatableComponent("otm.container.matter_panel.send"));
button.setDocking(Dock.RIGHT);
button.bindOnPress(() -> {
int value = 1; int value = 1;
try { try {
value = Integer.parseInt(input_amount.getValue()); value = Integer.parseInt(input_amount.getOrCreateWidget().getValue());
} catch (Exception ignored) { } catch (Exception ignored) {
} }
MatteryNetworking.CHANNEL.sendToServer(new PatternReplicationRequestPacket(open_pattern, value)); MatteryNetworking.CHANNEL.sendToServer(new PatternReplicationRequestPacket(state, value));
closePattern(); pattern_frame.remove();
} });
private void closePattern() { button.setDockMargin(2, 0, 0, 0);
open_pattern = null;
input_amount.visible = false;
input_amount.changeFocus(false);
inc_8.visible = false;
inc_64.visible = false;
inc_256.visible = false;
send_modal.visible = false; addPanel(pattern_frame);
cancel_modal.visible = false; pattern_frame.toScreenCenter();
popup(pattern_frame);
dec_8.visible = false;
dec_64.visible = false;
dec_256.visible = false;
}
private void openTask(MatterTask task) {
open_task = task;
close_task.visible = true;
cancel_task.visible = true;
}
private void closeTask() {
open_task = null;
close_task.visible = false;
cancel_task.visible = false;
}
private void cancelTask() {
menu.requestTaskCancel(open_task.id());
closeTask();
}
@Override
protected void containerTick() {
super.containerTick();
input_amount.tick();
}
@Override
public void resize(Minecraft p_96575_, int p_96576_, int p_96577_) {
var input_amount = this.input_amount;
super.resize(p_96575_, p_96576_, p_96577_);
if (open_task != null) {
openTask(open_task);
}
if (open_pattern != null) {
openPattern(open_pattern);
}
if (input_amount != null) {
this.input_amount.setValue(input_amount.getValue());
}
}
protected void renderForeground(PoseStack stack, int mouseX, int mouseY, float p_98421_) {
if (open_pattern != null) {
RenderSystem.disableDepthTest();
input_amount.render(stack, mouseX, mouseY, p_98421_);
RenderSystem.enableDepthTest();
RenderSystem.depthFunc(GL_ALWAYS);
inc_8.render(stack, mouseX, mouseY, p_98421_);
inc_64.render(stack, mouseX, mouseY, p_98421_);
inc_256.render(stack, mouseX, mouseY, p_98421_);
dec_8.render(stack, mouseX, mouseY, p_98421_);
dec_64.render(stack, mouseX, mouseY, p_98421_);
dec_256.render(stack, mouseX, mouseY, p_98421_);
dec_8.render(stack, mouseX, mouseY, p_98421_);
send_modal.render(stack, mouseX, mouseY, p_98421_);
cancel_modal.render(stack, mouseX, mouseY, p_98421_);
RenderSystem.depthFunc(GL_LESS);
} else if (open_task != null) {
RenderSystem.enableDepthTest();
RenderSystem.depthFunc(GL_ALWAYS);
cancel_task.render(stack, mouseX, mouseY, p_98421_);
close_task.render(stack, mouseX, mouseY, p_98421_);
RenderSystem.depthFunc(GL_LESS);
}
}
@Override
protected void renderLabels(PoseStack p_97808_, int p_97809_, int p_97810_) {}
@Nonnull
@Override
public List<Component> getTooltipFromItem(ItemStack p_96556_) {
List<Component> get_list = super.getTooltipFromItem(p_96556_);
if (hovered_pattern != null) {
get_list.add(new TranslatableComponent("otm.item.pattern.research", String.format("%.2f", hovered_pattern.research_percent() * 100d)).withStyle(ChatFormatting.AQUA));
} else if (hovered_task != null) {
get_list.add(new TranslatableComponent("otm.gui.matter_task.total", hovered_task.total()).withStyle(ChatFormatting.GRAY));
get_list.add(new TranslatableComponent("otm.gui.matter_task.required", hovered_task.required()).withStyle(ChatFormatting.GRAY));
get_list.add(new TranslatableComponent("otm.gui.matter_task.in_progress", hovered_task.in_progress()).withStyle(ChatFormatting.GRAY));
get_list.add(new TranslatableComponent("otm.gui.matter_task.finished", hovered_task.finished()).withStyle(ChatFormatting.GRAY));
}
return get_list;
}
@Override
protected void renderTooltip(PoseStack pose, int mouseX, int mouseY) {
if (open_pattern != null) {
int x = (width - modal_width) / 2 + 7;
int y = input_amount.y + 1;
if (mouseX >= x && mouseX <= x + 16 && mouseY >= y && mouseY <= y + 16) {
this.renderTooltip(pose, new ItemStack(open_pattern.item(), 1), mouseX, mouseY);
return;
}
} else if (hovered_pattern != null) {
this.renderTooltip(pose, new ItemStack(hovered_pattern.item(), 1), mouseX, mouseY);
return;
} else if (hovered_task != null) {
this.renderTooltip(pose, new ItemStack(hovered_task.item(), hovered_task.total()), mouseX, mouseY);
return;
}
super.renderTooltip(pose, mouseX, mouseY);
}
private void openPattern(PatternState state) {
open_pattern = state;
input_amount.setValue("1");
// input_amount.setFocus(true); // bugged
scrolling = false;
input_amount.visible = true;
inc_8.visible = true;
inc_64.visible = true;
inc_256.visible = true;
dec_8.visible = true;
dec_64.visible = true;
dec_256.visible = true;
send_modal.visible = true;
cancel_modal.visible = true;
}
private double scroller_position_regular = 0;
private double scroller_position_tasks = 0;
private void openTaskList() {
open_task_list = true;
scroller_position_regular = scroller_position;
scroller_position = scroller_position_tasks;
}
private void closeTaskList() {
open_task_list = false;
scroller_position_tasks = scroller_position;
scroller_position = scroller_position_regular;
}
@Override
public boolean mouseClicked(double mouse_x, double mouse_y, int p_97750_) {
if (open_task == null && open_pattern == null) {
if (hovered_pattern != null) {
openPattern(hovered_pattern);
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
return true;
} else if (hovered_task != null) {
openTask(hovered_task);
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
return true;
}
}
int button_x = leftPos + 157;
int button_y = topPos + 20 + (int) ((scroller_position / maxScroll()) * 145);
int button_width = 12;
int button_height = 15;
scrolling = maxScroll() > 0 && mouse_x >= button_x && button_x + button_width >= mouse_x && mouse_y >= button_y && button_y + button_height >= mouse_y;
if (open_task == null && open_pattern == null) {
if (open_task_list) {
button_x = leftPos;
button_y = topPos - 28;
button_width = 28;
button_height = 30;
if (mouse_x >= button_x && button_x + button_width >= mouse_x && mouse_y >= button_y && button_y + button_height >= mouse_y) {
closeTaskList();
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
}
} else {
button_x = leftPos + 28;
button_y = topPos - 28;
button_width = 28;
button_height = 30;
if (mouse_x >= button_x && button_x + button_width >= mouse_x && mouse_y >= button_y && button_y + button_height >= mouse_y) {
openTaskList();
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
}
}
}
return super.mouseClicked(mouse_x, mouse_y, p_97750_);
}
@Override
public boolean mouseReleased(double p_97812_, double p_97813_, int p_97814_) {
scrolling = false;
return super.mouseReleased(p_97812_, p_97813_, p_97814_);
}
@Override
public boolean mouseScrolled(double mouse_x, double mouse_y, double scroll) {
if (open_pattern != null) {
return true;
}
if (super.mouseScrolled(mouse_x, mouse_y, scroll)) {
return true;
}
scroller_position = Math.max(0, Math.min(maxScroll(), scroller_position - scroll));
return true;
}
@Override
public boolean mouseDragged(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) {
if (scrolling && maxScroll() > 0) {
if (mouse_y < topPos + 20) {
scroller_position = 0;
} else if (mouse_y > topPos + 20 + 160) {
scroller_position = maxScroll();
} else {
scroller_position = maxScroll() * (mouse_y - topPos - 20) / 160d;
}
}
return super.mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y);
}
private boolean scrolling = false;
private int maxScroll() {
if (open_task_list) {
if (menu.tasks.size() < 16) {
return 0;
}
return (int) Math.floor(menu.tasks.size() / 8d - 2d);
}
if (menu.patterns.size() < 16) {
return 0;
}
return (int) Math.floor(menu.patterns.size() / 8d - 2d);
}
@Override
protected void renderBg(PoseStack pose, float p_97788_, int mouseX, int mouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND());
if (open_task_list) {
// список паттернов
blit(pose, leftPos, topPos - 28, 176, 65, 28, 30);
} else {
// список задач
blit(pose, leftPos + 28, topPos - 28, 204, 65, 28, 30);
}
super.renderBg(pose, p_97788_, mouseX, mouseY);
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND());
if (maxScroll() > 0) {
if (scrolling) {
blit(pose, leftPos + 157, topPos + 20 + (int) ((scroller_position / maxScroll()) * 145), 188, 0, 12, 15);
} else {
blit(pose, leftPos + 157, topPos + 20 + (int) ((scroller_position / maxScroll()) * 145), 176, 0, 12, 15);
}
} else {
blit(pose, leftPos + 157, topPos + 20, 176, 0, 12, 15);
}
if (open_task_list) {
// список задач
blit(pose, leftPos + 28, topPos - 28, 204, 33, 28, 32);
} else {
// список паттернов
blit(pose, leftPos, topPos - 28, 176, 33, 28, 32);
}
this.font.draw(pose, this.title, (float) (leftPos + this.titleLabelX), (float) (topPos + this.titleLabelY), 4210752);
hovered_pattern = null;
hovered_task = null;
int cells_width = 8;
int cells_height = 9;
int render_x = leftPos + 10;
int render_y = topPos + 20;
int cell_x = 0;
int cell_y = 0;
RenderSystem.enableDepthTest();
if (open_task_list) {
for (int index = ((int) scroller_position) * 9; index < menu.tasks.size(); index++) {
var state = menu.tasks.get(index);
var itemstack = new ItemStack(state.item(), Math.max(1, state.required()));
// player, itemstack, x, y, ??????????
this.itemRenderer.renderAndDecorateItem(this.minecraft.player, itemstack, render_x, render_y, -1);
// font, itemstack, x, y, string
this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, render_x, render_y, null);
if (hovered_task == null && mouseX >= render_x && mouseX <= render_x + 16 && mouseY >= render_y && mouseY <= render_y + 16) {
hovered_task = state;
}
cell_x++;
render_x += 18;
if (cell_x >= cells_width) {
render_x = leftPos + 10;
render_y += 18;
cell_x = 0;
cell_y++;
if (cell_y >= cells_height)
break;
}
}
} else {
for (int index = ((int) scroller_position) * 9; index < menu.patterns.size(); index++) {
var state = menu.patterns.get(index);
var itemstack = new ItemStack(state.item(), 1);
// player, itemstack, x, y, ??????????
this.itemRenderer.renderAndDecorateItem(this.minecraft.player, itemstack, render_x, render_y, -1);
// font, itemstack, x, y, string
this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, render_x, render_y, null);
if (hovered_pattern == null && mouseX >= render_x && mouseX <= render_x + 16 && mouseY >= render_y && mouseY <= render_y + 16) {
hovered_pattern = state;
}
cell_x++;
render_x += 18;
if (cell_x >= cells_width) {
render_x = leftPos + 10;
render_y += 18;
cell_x = 0;
cell_y++;
if (cell_y >= cells_height)
break;
}
}
}
if (open_pattern != null || open_task != null) {
RenderSystem.depthFunc(GL_ALWAYS);
this.renderBackground(pose);
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, CONTAINER_BACKGROUND());
// PoseStack, x, y, image_start_x, image_start_y, rect_size_x, rect_size_y
int x = (width - modal_width) / 2;
int y = (height - modal_height) / 2;
// заголовок
int dy = 0;
this.blit(pose, x, y, 0, 188, modal_width, 4);
dy += 4;
for (; dy < modal_height - 10; dy += 5)
this.blit(pose, x, y + dy, 0, 192, modal_width, 5);
this.blit(pose, x, y + dy, 0, 197, modal_width, 4);
if (open_pattern != null) {
// фон слота
this.blit(pose, x + 6, input_amount.y, 176, 15, 18, 18);
} else {
this.blit(pose, x + 6, y + 19, 176, 15, 18, 18);
}
ItemStack itemstack;
if (open_pattern != null) {
itemstack = new ItemStack(open_pattern.item(), 1);
} else {
itemstack = new ItemStack(open_task.item(), 1);
}
RenderSystem.enableDepthTest();
if (open_pattern != null) {
// player, itemstack, x, y, ??????????
this.itemRenderer.renderAndDecorateItem(this.minecraft.player, itemstack, x + 7, input_amount.y + 1, 100);
// font, itemstack, x, y, string
this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, x + 7, input_amount.y + 1, null);
} else {
// player, itemstack, x, y, ??????????
this.itemRenderer.renderAndDecorateItem(this.minecraft.player, itemstack, x + 7, y + 20, 100);
// font, itemstack, x, y, string
// this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, x + 7, input_amount.y + 1, null);
}
if (open_pattern != null) {
this.font.draw(pose, new TranslatableComponent("otm.container.matter_panel.label"), (float) (x + 6), (float) (y + 5), 4210752);
this.font.draw(pose, new TranslatableComponent("otm.item.pattern.line", itemstack.getDisplayName(), String.format("%.2f", open_pattern.research_percent() * 100d)), (float) (x + 6), (float) (cancel_modal.y), ChatFormatting.AQUA.getColor());
} else {
this.font.draw(pose, new TranslatableComponent("otm.container.matter_panel.task"), (float) (x + 6), (float) (y + 5), 4210752);
this.font.draw(pose, new TranslatableComponent("otm.container.matter_panel.task_line", itemstack.getDisplayName(), open_task.in_progress(), open_task.finished(), open_task.total()), (float) (x + 27), (float) (y + 20), 4210752);
this.font.draw(pose, new TextComponent(open_task.id().toString().substring(0, 8) + "..."), (float) (x + 27), (float) (y + 30), 4210752);
}
RenderSystem.depthFunc(GL_LESS);
}
} }
} }

View File

@ -105,6 +105,7 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
protected final ArrayList<EditablePanel> panels = new ArrayList<>(); protected final ArrayList<EditablePanel> panels = new ArrayList<>();
public FramePanel inventory_frame; public FramePanel inventory_frame;
public FramePanel main_frame; public FramePanel main_frame;
private boolean made_main_frame = false;
public MatteryScreen(T menu, Inventory inventory, Component title) { public MatteryScreen(T menu, Inventory inventory, Component title) {
super(menu, inventory, title); super(menu, inventory, title);
@ -125,22 +126,6 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
slot); slot);
} }
} }
main_frame = makeMainFrame();
if (main_frame != null) {
addPanel(main_frame);
for (var widget : menu.mattery_widgets) {
new MatteryWidgetPanel(this, main_frame, widget);
}
for (var slot : menu.main_slots) {
new SlotPanel<>(this, main_frame, slot);
}
}
movePanels();
} }
public void addPanel(EditablePanel panel) { public void addPanel(EditablePanel panel) {
@ -148,6 +133,10 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
panels.add(panel); panels.add(panel);
} }
public void removePanel(EditablePanel panel) {
panels.remove(panel);
}
@Nullable @Nullable
protected FramePanel makeMainFrame() { protected FramePanel makeMainFrame() {
return new FramePanel(this, null, 0, 0, 18 * 9 + 16, 100, getTitle()); return new FramePanel(this, null, 0, 0, 18 * 9 + 16, 100, getTitle());
@ -208,16 +197,18 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
@Override @Override
public boolean mouseClicked(double p_97748_, double p_97749_, int p_97750_) { public boolean mouseClicked(double p_97748_, double p_97749_, int p_97750_) {
var happen_to_click = false;
for (int i = panels.size() - 1; i >= 0; i--) { for (int i = panels.size() - 1; i >= 0; i--) {
var panel = panels.get(i); var panel = panels.get(i);
if (panel.mouseClickedChecked(p_97748_, p_97749_, p_97750_)) { if (happen_to_click) {
return true; panel.killFocus();
} else if (panel.mouseClickedChecked(p_97748_, p_97749_, p_97750_)) {
happen_to_click = true;
} }
} }
// this.slotClicked(null, -999, p_97750_, ClickType.THROW);
return true; return true;
} }
@ -263,6 +254,32 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
return true; return true;
} }
@Override
public boolean keyReleased(int p_94715_, int p_94716_, int p_94717_) {
for (int i = panels.size() - 1; i >= 0; i--) {
var panel = panels.get(i);
if (panel.keyReleased(p_94715_, p_94716_, p_94717_)) {
return true;
}
}
return true;
}
@Override
public boolean charTyped(char p_94683_, int p_94684_) {
for (int i = panels.size() - 1; i >= 0; i--) {
var panel = panels.get(i);
if (panel.charTyped(p_94683_, p_94684_)) {
return true;
}
}
return true;
}
@Override @Override
public boolean keyPressed(int p_97765_, int p_97766_, int p_97767_) { public boolean keyPressed(int p_97765_, int p_97766_, int p_97767_) {
InputConstants.Key mouseKey = InputConstants.getKey(p_97765_, p_97766_); InputConstants.Key mouseKey = InputConstants.getKey(p_97765_, p_97766_);
@ -319,6 +336,25 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
@Override @Override
public void render(PoseStack pose, int mouse_x, int mouse_y, float flag) { public void render(PoseStack pose, int mouse_x, int mouse_y, float flag) {
if (!made_main_frame) {
made_main_frame = true;
main_frame = makeMainFrame();
if (main_frame != null) {
addPanel(main_frame);
for (var widget : menu.mattery_widgets) {
new MatteryWidgetPanel(this, main_frame, widget);
}
for (var slot : menu.main_slots) {
new SlotPanel<>(this, main_frame, slot);
}
}
movePanels();
}
int render_x = this.leftPos; int render_x = this.leftPos;
int render_y = this.topPos; int render_y = this.topPos;
@ -381,7 +417,8 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
RenderSystem.disableDepthTest(); RenderSystem.disableDepthTest();
// forge's hard limit on tooltip Z position // forge's hard limit tooltip Z position to 500 units
// so if we have anything drawn above 500 units, lift it up
if (depth > 500) { if (depth > 500) {
pose.pushPose(); pose.pushPose();
pose.translate(0, 0, depth - 500); pose.translate(0, 0, depth - 500);
@ -391,8 +428,12 @@ public abstract class MatteryScreen<T extends MatteryMenu> extends AbstractConta
if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) { if (this.hoveredSlot != null && this.hoveredSlot.hasItem()) {
this.renderTooltip(pose, this.hoveredSlot.getItem(), mouse_x, mouse_y); this.renderTooltip(pose, this.hoveredSlot.getItem(), mouse_x, mouse_y);
} else { } else {
for (var panel : panels) { for (int i = panels.size() - 1; i >= 0; i--) {
panel.renderTooltips(pose, mouse_x, mouse_y, flag); var panel = panels.get(i);
if (panel.renderTooltips(pose, mouse_x, mouse_y, flag)) {
break;
}
} }
} }
} }

View File

@ -10,6 +10,8 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters;
/** /**
* I am too lazy to learn how Mojang's API works * I am too lazy to learn how Mojang's API works
* so I just recreate part of GMod's API in here * so I just recreate part of GMod's API in here
*
* also contains texture widgets
*/ */
public class RenderHelper { public class RenderHelper {
private static final Matrix4f identity = new Matrix4f(); private static final Matrix4f identity = new Matrix4f();
@ -182,6 +184,8 @@ public class RenderHelper {
public record SkinElement(ResourceLocation texture, float image_x, float image_y, float rect_w, float rect_h, float defined_width, float defined_height) { public record SkinElement(ResourceLocation texture, float image_x, float image_y, float rect_w, float rect_h, float defined_width, float defined_height) {
public void render(PoseStack stack, float x, float y, float width, float height) { public void render(PoseStack stack, float x, float y, float width, float height) {
RenderSystem.setShaderTexture(0, texture); RenderSystem.setShaderTexture(0, texture);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
drawTexturedRectUV( drawTexturedRectUV(
stack, stack,
@ -195,6 +199,57 @@ public class RenderHelper {
(image_y + rect_h) / defined_height); (image_y + rect_h) / defined_height);
} }
public void render(PoseStack stack, float x, float y) {
RenderSystem.setShaderTexture(0, texture);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
drawTexturedRectUV(
stack,
x,
y,
rect_w,
rect_h,
image_x / defined_width,
image_y / defined_height,
(image_x + rect_w) / defined_width,
(image_y + rect_h) / defined_height);
}
public void renderW(PoseStack stack, float x, float y, float width) {
RenderSystem.setShaderTexture(0, texture);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
drawTexturedRectUV(
stack,
x,
y,
width,
rect_h,
image_x / defined_width,
image_y / defined_height,
(image_x + rect_w) / defined_width,
(image_y + rect_h) / defined_height);
}
public void renderH(PoseStack stack, float x, float y, float height) {
RenderSystem.setShaderTexture(0, texture);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
drawTexturedRectUV(
stack,
x,
y,
rect_w,
height,
image_x / defined_width,
image_y / defined_height,
(image_x + rect_w) / defined_width,
(image_y + rect_h) / defined_height);
}
public void renderRaw(PoseStack stack, float x, float y, float width, float height) { public void renderRaw(PoseStack stack, float x, float y, float width, float height) {
// RenderSystem.setShader(GameRenderer::getPositionTexShader); // RenderSystem.setShader(GameRenderer::getPositionTexShader);
// RenderSystem.setShaderTexture(0, texture); // RenderSystem.setShaderTexture(0, texture);
@ -210,9 +265,25 @@ public class RenderHelper {
(image_x + rect_w) / defined_width, (image_x + rect_w) / defined_width,
(image_y + rect_h) / defined_height); (image_y + rect_h) / defined_height);
} }
public void renderRaw(PoseStack stack, float x, float y) {
// RenderSystem.setShader(GameRenderer::getPositionTexShader);
// RenderSystem.setShaderTexture(0, texture);
drawTexturedRectUV(
stack,
x,
y,
rect_w,
rect_h,
image_x / defined_width,
image_y / defined_height,
(image_x + rect_w) / defined_width,
(image_y + rect_h) / defined_height);
}
} }
public static final SkinElement upper_left_window_corner = new SkinElement( public static final SkinElement top_left_window_corner = new SkinElement(
WIDGETS, WIDGETS,
18, 18,
0, 0,
@ -222,7 +293,7 @@ public class RenderHelper {
256 256
); );
public static final SkinElement upper_right_window_corner = new SkinElement( public static final SkinElement top_right_window_corner = new SkinElement(
WIDGETS, WIDGETS,
24, 24,
0, 0,
@ -294,14 +365,110 @@ public class RenderHelper {
public static final SkinElement window_background = new SkinElement( public static final SkinElement window_background = new SkinElement(
WIDGETS, WIDGETS,
22, 30,
4, 12,
4, 6,
4, 6,
256, 256,
256 256
); );
public static final SkinElement scroll_bar_top = new SkinElement(
WIDGETS,
18,
57,
14,
2,
256,
256
);
public static final SkinElement scroll_bar_bottom = new SkinElement(
WIDGETS,
18,
63,
14,
2,
256,
256
);
public static final SkinElement scroll_bar_body = new SkinElement(
WIDGETS,
18,
58,
14,
6,
256,
256
);
public static final SkinElement scroll_bar_button = new SkinElement(
WIDGETS,
18,
12,
12,
15,
256,
256
);
public static final SkinElement scroll_bar_button_hover = new SkinElement(
WIDGETS,
18,
27,
12,
15,
256,
256
);
public static final SkinElement scroll_bar_button_press = new SkinElement(
WIDGETS,
18,
42,
12,
15,
256,
256
);
public static final SkinElement tab_right_connection = new SkinElement(
WIDGETS,
30,
0,
3,
5,
256,
256
);
public static final SkinElement tab_left_connection = new SkinElement(
WIDGETS,
33,
0,
3,
5,
256,
256
);
public static final SkinElement tab_background = new SkinElement(
WIDGETS,
30,
6,
6,
6,
256,
256
);
public static void drawScrollBarBackground(PoseStack stack, float x, float y, float height) {
scroll_bar_body.render(stack, x, y + 2, 14, height - 4);
scroll_bar_top.render(stack, x, y, 14, 2);
scroll_bar_bottom.render(stack, x, y + height - 2, 14, 2);
}
public static void drawRegularSlot( public static void drawRegularSlot(
PoseStack stack, PoseStack stack,
float x, float x,
@ -343,8 +510,8 @@ public class RenderHelper {
bottom_window_border.renderRaw(stack, x + 4, y + height - 3, width - 8, 3); bottom_window_border.renderRaw(stack, x + 4, y + height - 3, width - 8, 3);
// corners // corners
upper_left_window_corner.renderRaw(stack, x, y, 6, 6); top_left_window_corner.renderRaw(stack, x, y, 6, 6);
upper_right_window_corner.renderRaw(stack, x + width - 6, y, 6, 6); top_right_window_corner.renderRaw(stack, x + width - 6, y, 6, 6);
bottom_left_window_corner.renderRaw(stack, x, y + height - 6, 6, 6); bottom_left_window_corner.renderRaw(stack, x, y + height - 6, 6, 6);
bottom_right_window_corner.renderRaw(stack, x + width - 6, y + height - 6, 6, 6); bottom_right_window_corner.renderRaw(stack, x + width - 6, y + height - 6, 6, 6);

View File

@ -0,0 +1,113 @@
package ru.dbotthepony.mc.otm.screen.panels;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.menu.slot.MatterySlot;
import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import ru.dbotthepony.mc.otm.screen.RGBAColor;
import ru.dbotthepony.mc.otm.screen.RenderHelper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public abstract class AbstractSlotPanel extends EditablePanel {
public AbstractSlotPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height) {
super(screen, parent, x, y, width, height);
}
public AbstractSlotPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y) {
super(screen, parent, x, y, REGULAR_DIMENSIONS, REGULAR_DIMENSIONS);
}
public static final RGBAColor SLOT_HIGHLIGHT = new RGBAColor(255, 255, 255, 100);
public static final RGBAColor SLOT_HIGHLIGHT_DRAG = new RGBAColor(200, 200, 200, 150);
public static final int REGULAR_DIMENSIONS = 18;
protected void renderSlotBackground(PoseStack stack, float mouse_x, float mouse_y, float flag) {
RenderHelper.drawRegularSlot(stack, 0, 0);
}
protected void renderRegular(PoseStack stack, ItemStack itemstack) {
renderRegular(stack, itemstack, null);
}
protected void renderRegular(PoseStack stack, ItemStack itemstack, @Nullable String count_override) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
float height = 0;
if (!itemstack.isEmpty()) {
RenderSystem.enableDepthTest();
var system_stack = RenderSystem.getModelViewStack();
system_stack.pushPose();
system_stack.translate(parent_x + 1, parent_y + 1, 0);
RenderSystem.applyModelViewMatrix();
// Thanks Mojang
// Very cool
// (for int x, int y, which are then cast into doubles anyway)
screen.getItemRenderer().blitOffset = accumulated_depth - 100; // force item to draw only 50 units "above" background
screen.getItemRenderer().renderAndDecorateItem(Minecraft.getInstance().player, itemstack, 0, 0, (int) (parent_x + parent_y * 1000) /* some kind of indexing ? */);
screen.getItemRenderer().renderGuiItemDecorations(screen.getFont(), itemstack, 0, 0, count_override);
// too big accumulations can lead to Z near clipping issues
accumulate3DHeight(101);
height = 101;
system_stack.popPose();
RenderSystem.applyModelViewMatrix();
}
if (is_hovered) {
stack.pushPose();
stack.translate(0, 0, height);
RenderHelper.setDrawColor(SLOT_HIGHLIGHT);
RenderHelper.drawRect(stack, 1, 1, getWidth() - 1, getHeight() - 1);
stack.popPose();
}
}
@Nonnull
abstract protected ItemStack getItemStack();
protected List<Component> getItemStackTooltip(ItemStack stack) {
return screen.getTooltipFromItem(stack);
}
@Override
protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) {
renderSlotBackground(stack, mouse_x, mouse_y, flag);
renderRegular(stack, getItemStack());
}
@Override
protected boolean innerRenderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) {
if (is_hovered) {
var itemstack = getItemStack();
if (!itemstack.isEmpty()) {
Font font = net.minecraftforge.client.RenderProperties.get(itemstack).getFont(itemstack);
net.minecraftforge.fmlclient.gui.GuiUtils.preItemToolTip(itemstack);
screen.renderComponentToolTip(stack, getItemStackTooltip(itemstack), (int) mouse_x, (int) mouse_y, (font == null ? screen.getFont() : font));
net.minecraftforge.fmlclient.gui.GuiUtils.postItemToolTip();
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,33 @@
package ru.dbotthepony.mc.otm.screen.panels;
import net.minecraft.client.gui.components.Button;
import net.minecraft.network.chat.Component;
import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class ButtonPanel extends MinecraftWidgetPanel<Button> {
protected Runnable press_callback;
public ButtonPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Component label) {
super(screen, parent, x, y, width, height, (panel) -> {
return new Button(0, 0, (int) panel.getWidth(), (int) panel.getHeight(), label, (btn) -> ((ButtonPanel) panel).onPress()) {
@Override
public boolean isHovered() {
return panel.is_hovered;
}
};
});
}
public void bindOnPress(Runnable runnable) {
press_callback = runnable;
}
protected void onPress() {
if (press_callback != null) {
press_callback.run();
}
}
}

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.screen.panels;
import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.screen.MatteryScreen; import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -11,7 +12,12 @@ import javax.annotation.Nullable;
public class EditBoxPanel extends MinecraftWidgetPanel<EditBox> { public class EditBoxPanel extends MinecraftWidgetPanel<EditBox> {
public EditBoxPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Component component) { public EditBoxPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Component component) {
super(screen, parent, x, y, width, height, (panel) -> { super(screen, parent, x, y, width, height, (panel) -> {
return new EditBox(screen.getFont(), 0, 0, (int) panel.getWidth(), (int) panel.getHeight(), component); return new EditBox(screen.getFont(), 0, 0, (int) panel.getWidth(), (int) panel.getHeight(), component) {
@Override
public boolean isHovered() {
return panel.is_hovered;
}
};
}); });
} }
@ -20,14 +26,30 @@ public class EditBoxPanel extends MinecraftWidgetPanel<EditBox> {
new_widget.setValue(old_widget.getValue()); new_widget.setValue(old_widget.getValue());
} }
@Override
public void tick() {
if (widget != null)
widget.tick();
}
@Override
protected void factorize(EditBox widget, boolean recreation) {
widget.setFocus(focused);
}
@Override @Override
protected void onFocusChanged(boolean new_focused, boolean old_focused) { protected void onFocusChanged(boolean new_focused, boolean old_focused) {
widget.setFocus(new_focused); OverdriveThatMatters.LOGGER.info("Focus {}", new_focused);
getOrCreateWidget().setFocus(new_focused);
} }
@Override @Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) { protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
if (super.mouseClickedInner(mouse_x, mouse_y, flag)) {
requestFocus(); requestFocus();
return widget.mouseClicked(mouse_x, mouse_y, flag); return true;
}
return false;
} }
} }

View File

@ -3,11 +3,13 @@ package ru.dbotthepony.mc.otm.screen.panels;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.components.events.GuiEventListener;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.screen.MatteryScreen; import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
/** /**
* Superclass of all panels * Superclass of all panels
@ -28,9 +30,12 @@ public class EditablePanel implements GuiEventListener {
protected boolean focused = false; protected boolean focused = false;
private boolean focused_internal = false; private boolean focused_internal = false;
// updated from render
// tells whenever is mouse within this panel's boundaries /**
// doesn't tell whenever it is hovered directly above and not on children * updated from render;
* tells whenever is mouse within this panel's boundaries;
* doesn't tell whenever it is hovered directly above and not on it's children
*/
public boolean is_hovered = false; public boolean is_hovered = false;
// relative to parent // relative to parent
@ -38,10 +43,18 @@ public class EditablePanel implements GuiEventListener {
private float x; private float x;
private float y; private float y;
// minimal coordinates, can be negative
private float bound_x;
private float bound_y;
// updated inside performLayout depending on dock // updated inside performLayout depending on dock
private float width; private float width;
private float height; private float height;
// maximal coordinates, can be negative
private float bound_width;
private float bound_height;
// updated on each rendered frame // updated on each rendered frame
protected float parent_x; protected float parent_x;
protected float parent_y; protected float parent_y;
@ -86,6 +99,10 @@ public class EditablePanel implements GuiEventListener {
invalidateLayout(); invalidateLayout();
} }
public EditablePanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent) {
this(screen, parent, 0, 0, 10, 10);
}
public float getRenderX() { public float getRenderX() {
return parent_x; return parent_x;
} }
@ -98,8 +115,15 @@ public class EditablePanel implements GuiEventListener {
} }
protected void innerRenderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) { /**
* @param stack
* @param mouse_x
* @param mouse_y
* @param flag
* @return whenever have we drawn a tooltip
*/
protected boolean innerRenderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) {
return false;
} }
/** /**
@ -126,7 +150,6 @@ public class EditablePanel implements GuiEventListener {
if (parent == null) { if (parent == null) {
parent_x = x; parent_x = x;
parent_y = y; parent_y = y;
} else { } else {
is_hovered = parent.is_hovered && mouse_x >= parent_x && mouse_x <= parent_x + width && mouse_y >= parent_y && mouse_y <= parent_y + height; is_hovered = parent.is_hovered && mouse_x >= parent_x && mouse_x <= parent_x + width && mouse_y >= parent_y && mouse_y <= parent_y + height;
} }
@ -169,20 +192,26 @@ public class EditablePanel implements GuiEventListener {
* @param mouse_y * @param mouse_y
* @param flag * @param flag
*/ */
public void renderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) { public boolean renderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) {
if (!getVisible()) { if (!getVisible()) {
return; return false;
} }
innerRenderTooltips(stack, mouse_x, mouse_y, flag); if (innerRenderTooltips(stack, mouse_x, mouse_y, flag)) {
return true;
}
for (var child : children) { for (var child : children) {
if (child.getVisible()) { if (child.getVisible()) {
child.innerRenderTooltips(stack, mouse_x, mouse_y, flag); if (child.renderTooltips(stack, mouse_x, mouse_y, flag)) {
return true;
} }
} }
} }
return false;
}
public void setDocking(Dock docking) { public void setDocking(Dock docking) {
if (docking != this.docking) { if (docking != this.docking) {
this.docking = docking; this.docking = docking;
@ -202,11 +231,11 @@ public class EditablePanel implements GuiEventListener {
} }
} }
public DockProperty getDock_margin() { public DockProperty getDockMargin() {
return dock_margin; return dock_margin;
} }
public DockProperty getDock_padding() { public DockProperty getDockPadding() {
return dock_padding; return dock_padding;
} }
@ -331,6 +360,14 @@ public class EditablePanel implements GuiEventListener {
if (old_visible != new_visible) { if (old_visible != new_visible) {
visibilityChanges(new_visible, old_visible); visibilityChanges(new_visible, old_visible);
if (parent != null) {
parent.invalidateLayout();
}
if (new_visible) {
killFocus();
}
} }
updateVisible(); updateVisible();
@ -347,14 +384,20 @@ public class EditablePanel implements GuiEventListener {
return this; return this;
for (var child : children) { for (var child : children) {
if (child.focused) { var get_focus = child.getHierarchicalFocus();
return child.getHierarchicalFocus();
if (get_focus != null) {
return get_focus;
} }
} }
return null; return null;
} }
protected void onHierarchicalFocusChanged(boolean new_focused, boolean old_focused) {
}
protected void onFocusChanged(boolean new_focused, boolean old_focused) { protected void onFocusChanged(boolean new_focused, boolean old_focused) {
} }
@ -364,7 +407,7 @@ public class EditablePanel implements GuiEventListener {
focused_internal = hasHierarchicalFocus(); focused_internal = hasHierarchicalFocus();
if (focused_internal != old_value) { if (focused_internal != old_value) {
onFocusChanged(focused_internal, old_value); onHierarchicalFocusChanged(focused_internal, old_value);
} }
for (var child : children) { for (var child : children) {
@ -382,7 +425,9 @@ public class EditablePanel implements GuiEventListener {
public void setFocused(boolean focused) { public void setFocused(boolean focused) {
if (this.focused != focused) { if (this.focused != focused) {
var old = this.focused;
this.focused = focused; this.focused = focused;
onFocusChanged(focused, old);
getRootPanel().updateFocused(); getRootPanel().updateFocused();
} }
} }
@ -408,15 +453,19 @@ public class EditablePanel implements GuiEventListener {
} }
} }
public void killFocus() { private void killFocusInernal() {
if (this.focused_internal) { for (var child : children) {
var child = getHierarchicalFocus(); child.killFocusInernal();
while (child != null) {
child.setFocused(false);
child = getHierarchicalFocus();
} }
if (focused) {
setFocused(false);
}
}
public void killFocus() {
if (this.focused_internal) {
killFocusInernal();
getRootPanel().updateFocused(); getRootPanel().updateFocused();
} }
} }
@ -534,6 +583,26 @@ public class EditablePanel implements GuiEventListener {
} }
} }
public List<EditablePanel> getChildren() {
return List.copyOf(children);
}
protected ArrayList<EditablePanel> getChildrenInternal() {
return children;
}
@Nullable
public EditablePanel childAtIndex(int index) {
if (index < 0 || index >= children.size()) {
return null;
}
return children.get(index);
}
/**
* Align and rescale children here
*/
protected void performLayout() { protected void performLayout() {
var dock_left = dock_padding.left; var dock_left = dock_padding.left;
var dock_right = dock_padding.right; var dock_right = dock_padding.right;
@ -542,12 +611,20 @@ public class EditablePanel implements GuiEventListener {
// determine sizes // determine sizes
for (var child : children) { for (var child : children) {
if (child.getVisible()) {
switch (child.docking) { switch (child.docking) {
case TOP -> dock_top += child.height + child.dock_margin.top; case TOP -> dock_top += child.height + child.dock_margin.top;
case BOTTOM -> dock_bottom += child.height + child.dock_margin.bottom; case BOTTOM -> dock_bottom += child.height + child.dock_margin.bottom;
case LEFT -> dock_left += child.width + child.dock_margin.left; case LEFT -> dock_left += child.width + child.dock_margin.left;
case RIGHT -> dock_right += child.width + child.dock_margin.right; case RIGHT -> dock_right += child.width + child.dock_margin.right;
} }
bound_x = Math.min(bound_x, child.x);
bound_y = Math.min(bound_y, child.y);
bound_width = Math.max(bound_width, child.x + child.width);
bound_height = Math.max(bound_height, child.y + child.height);
}
} }
var dock_left2 = dock_padding.left; var dock_left2 = dock_padding.left;
@ -557,6 +634,7 @@ public class EditablePanel implements GuiEventListener {
// apply values // apply values
for (var child : children) { for (var child : children) {
if (child.getVisible()) {
switch (child.docking) { switch (child.docking) {
case TOP -> { case TOP -> {
child.setPos(dock_left + child.dock_margin.left, dock_top2 + child.dock_margin.top); child.setPos(dock_left + child.dock_margin.left, dock_top2 + child.dock_margin.top);
@ -585,6 +663,34 @@ public class EditablePanel implements GuiEventListener {
} }
} }
for (var child : children) {
if (child.getVisible()) {
if (child.docking == Dock.FILL) {
child.setDimensions(
dock_left2 + child.dock_margin.left,
dock_top2 + child.dock_margin.top,
width - child.dock_margin.left - child.dock_margin.right - dock_right2 - dock_left2,
height - child.dock_margin.bottom - child.dock_margin.top - dock_bottom2 - dock_top2);
}
}
}
bound_x = 0;
bound_y = 0;
bound_width = 0;
bound_height = 0;
for (var child : children) {
if (child.getVisible()) {
bound_x = Math.min(bound_x, child.x);
bound_y = Math.min(bound_y, child.y);
bound_width = Math.max(bound_width, child.x + child.width);
bound_height = Math.max(bound_height, child.y + child.height);
}
}
}
private boolean accept_mouse_input = true; private boolean accept_mouse_input = true;
private boolean accept_keyboard_input = true; private boolean accept_keyboard_input = true;
private boolean ignore_mouse_event_boundaries = false; private boolean ignore_mouse_event_boundaries = false;
@ -636,6 +742,16 @@ public class EditablePanel implements GuiEventListener {
return false; return false;
} }
public boolean withinBounds(double mouse_x, double mouse_y) {
var pos = localToScreen();
return pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y;
}
public boolean withinExtendedBounds(double mouse_x, double mouse_y) {
var pos = localToScreen(bound_x, bound_y);
return pos.x <= mouse_x && pos.x + bound_width >= mouse_x && pos.y <= mouse_y && pos.y + bound_height >= mouse_y;
}
@Override @Override
public boolean mouseClicked(double mouse_x, double mouse_y, int flag) { public boolean mouseClicked(double mouse_x, double mouse_y, int flag) {
if (!getVisible() || !getMouseInputEnabled()) if (!getVisible() || !getMouseInputEnabled())
@ -645,10 +761,8 @@ public class EditablePanel implements GuiEventListener {
return mouseClickedInner(mouse_x, mouse_y, flag); return mouseClickedInner(mouse_x, mouse_y, flag);
for (var child : children) { for (var child : children) {
var pos = child.localToScreen(); if (child.mouseClickedChecked(mouse_x, mouse_y, flag)) {
return true;
if (child.getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + child.width >= mouse_x && pos.y <= mouse_y && pos.y + child.height >= mouse_y) {
return child.mouseClicked(mouse_x, mouse_y, flag);
} else if (child.auto_kill_focus) { } else if (child.auto_kill_focus) {
child.killFocus(); child.killFocus();
} }
@ -658,17 +772,28 @@ public class EditablePanel implements GuiEventListener {
} }
public boolean mouseClickedChecked(double mouse_x, double mouse_y, int flag) { public boolean mouseClickedChecked(double mouse_x, double mouse_y, int flag) {
if (!getVisible()) if (!getVisible() || !getMouseInputEnabled())
return false; return false;
var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) {
if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) {
if (getMouseInputEnabled() && parent == null) if (getMouseInputEnabled() && parent == null)
screen.popup(this); screen.popup(this);
mouseClicked(mouse_x, mouse_y, flag); mouseClicked(mouse_x, mouse_y, flag);
return true; return true;
} else if (withinExtendedBounds(mouse_x, mouse_y)) {
for (var child : children) {
if (child.mouseClickedChecked(mouse_x, mouse_y, flag)) {
return true;
} else if (child.auto_kill_focus) {
child.killFocus();
}
}
if (auto_kill_focus)
killFocus();
} else if (auto_kill_focus) {
killFocus();
} }
return false; return false;
@ -687,10 +812,8 @@ public class EditablePanel implements GuiEventListener {
return mouseReleasedInner(mouse_x, mouse_y, flag); return mouseReleasedInner(mouse_x, mouse_y, flag);
for (var child : children) { for (var child : children) {
var pos = child.localToScreen(); if (child.mouseReleasedChecked(mouse_x, mouse_y, flag)) {
return true;
if (child.getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + child.width >= mouse_x && pos.y <= mouse_y && pos.y + child.height >= mouse_y) {
return child.mouseReleased(mouse_x, mouse_y, flag);
} }
} }
@ -698,14 +821,18 @@ public class EditablePanel implements GuiEventListener {
} }
public boolean mouseReleasedChecked(double mouse_x, double mouse_y, int flag) { public boolean mouseReleasedChecked(double mouse_x, double mouse_y, int flag) {
if (!getVisible()) if (!getVisible() || !getMouseInputEnabled())
return false; return false;
var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) {
if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) {
mouseReleased(mouse_x, mouse_y, flag); mouseReleased(mouse_x, mouse_y, flag);
return true; return true;
} else if (withinExtendedBounds(mouse_x, mouse_y)) {
for (var child : children) {
if (child.mouseReleasedChecked(mouse_x, mouse_y, flag)) {
return true;
}
}
} }
return false; return false;
@ -724,10 +851,8 @@ public class EditablePanel implements GuiEventListener {
return mouseDraggedInner(mouse_x, mouse_y, flag, drag_x, drag_y); return mouseDraggedInner(mouse_x, mouse_y, flag, drag_x, drag_y);
for (var child : children) { for (var child : children) {
var pos = child.localToScreen(); if (child.mouseDraggedChecked(mouse_x, mouse_y, flag, drag_x, drag_y)) {
return true;
if (child.getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + child.width >= mouse_x && pos.y <= mouse_y && pos.y + child.height >= mouse_y) {
return child.mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y);
} }
} }
@ -735,44 +860,57 @@ public class EditablePanel implements GuiEventListener {
} }
public boolean mouseDraggedChecked(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) { public boolean mouseDraggedChecked(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) {
if (!getVisible()) if (!getVisible() || !getMouseInputEnabled())
return false; return false;
var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) {
if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) {
mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y); mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y);
return true; return true;
} else if (withinExtendedBounds(mouse_x, mouse_y)) {
for (var child : children) {
if (child.mouseDraggedChecked(mouse_x, mouse_y, flag, drag_x, drag_y)) {
return true;
}
}
} }
return false; return false;
} }
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
return false;
}
@Override @Override
public boolean mouseScrolled(double mouse_x, double mouse_y, double scroll) { public boolean mouseScrolled(double mouse_x, double mouse_y, double scroll) {
if (!getVisible() || !getMouseInputEnabled()) if (!getVisible() || !getMouseInputEnabled())
return false; return false;
if (ignore_mouse_event_boundaries)
return mouseScrolledInner(mouse_x, mouse_y, scroll);
for (var child : children) { for (var child : children) {
var pos = child.localToScreen(); if (child.mouseScrolledChecked(mouse_x, mouse_y, scroll)) {
return true;
if (child.getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + child.width >= mouse_x && pos.y <= mouse_y && pos.y + child.height >= mouse_y) {
return child.mouseScrolled(mouse_x, mouse_y, scroll);
} }
} }
return GuiEventListener.super.mouseScrolled(mouse_x, mouse_y, scroll); return mouseScrolledInner(mouse_x, mouse_y, scroll);
} }
public boolean mouseScrolledChecked(double mouse_x, double mouse_y, double scroll) { public boolean mouseScrolledChecked(double mouse_x, double mouse_y, double scroll) {
if (!getVisible()) if (!getVisible() || !getMouseInputEnabled())
return false; return false;
var pos = localToScreen(); if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) {
if (getIgnoreMouseEventBoundaries() || pos.x <= mouse_x && pos.x + width >= mouse_x && pos.y <= mouse_y && pos.y + height >= mouse_y) {
mouseScrolled(mouse_x, mouse_y, scroll); mouseScrolled(mouse_x, mouse_y, scroll);
return true; return true;
} else if (withinExtendedBounds(mouse_x, mouse_y)) {
for (var child : children) {
if (child.mouseScrolledChecked(mouse_x, mouse_y, scroll)) {
return true;
}
}
} }
return false; return false;
@ -826,11 +964,21 @@ public class EditablePanel implements GuiEventListener {
return false; return false;
} }
protected boolean charTypedInternal(char p_94732_, int p_94733_) {
return false;
}
@Override @Override
public boolean charTyped(char p_94732_, int p_94733_) { public boolean charTyped(char p_94732_, int p_94733_) {
if (!getVisible() || !getKeyboardInputEnabled()) if (!getVisible() || !getKeyboardInputEnabled())
return false; return false;
if (!focused_internal)
return false;
if (focused)
return charTypedInternal(p_94732_, p_94733_);
for (var child : children) { for (var child : children) {
if (child.charTyped(p_94732_, p_94733_)) { if (child.charTyped(p_94732_, p_94733_)) {
return true; return true;
@ -863,4 +1011,25 @@ public class EditablePanel implements GuiEventListener {
public void tick() { public void tick() {
} }
private boolean is_removed = false;
protected void onRemoved() {
}
public void remove() {
if (is_removed) {
return;
}
killFocus();
screen.removePanel(this);
for (var child : children) {
child.remove();
}
onRemoved();
}
} }

View File

@ -1,23 +1,188 @@
package ru.dbotthepony.mc.otm.screen.panels; package ru.dbotthepony.mc.otm.screen.panels;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.narration.NarratableEntry; import net.minecraft.client.gui.narration.NarratableEntry;
import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import ru.dbotthepony.mc.otm.screen.MatteryScreen; import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import ru.dbotthepony.mc.otm.screen.RenderHelper; import ru.dbotthepony.mc.otm.screen.RenderHelper;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList;
public class FramePanel extends EditablePanel implements NarratableEntry { public class FramePanel extends EditablePanel implements NarratableEntry {
public enum FrameTabPosition {
TOP(28, 28,28, 32),
LEFT(28, 28, 32, 28),
RIGHT(28, 28, 32, 28),
BOTTOM(28, 28, 28, 32);
public final int width;
public final int height;
public final int active_width;
public final int active_height;
FrameTabPosition(int width, int height, int active_width, int active_height) {
this.width = width;
this.height = height;
this.active_width = active_width;
this.active_height = active_height;
}
}
public class FrameTabPanel extends EditablePanel {
public final FrameTabPosition tab_position;
public boolean isActive() {
return active;
}
protected boolean active = false;
protected boolean initial = false;
protected Runnable on_open;
protected Runnable on_close;
public FrameTabPanel(FrameTabPosition position, Runnable on_open, Runnable on_close) {
super(FramePanel.this.screen, FramePanel.this, 0, 0, position.width, position.height);
tab_position = position;
this.on_open = on_open;
this.on_close = on_close;
}
@Override
protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) {
if (tab_position == FrameTabPosition.TOP) {
int width;
int height;
if (active) {
width = tab_position.active_width;
height = tab_position.active_height;
RenderHelper.window_background.render(stack, 2, 2, width - 4, height - 2);
} else {
width = tab_position.width;
height = tab_position.height;
RenderHelper.tab_background.render(stack, 2, 2, width - 4, height - 2);
}
RenderHelper.top_window_border.renderW(stack, 3, 0, width - 6);
RenderHelper.left_window_border.renderH(stack, 0, 3, height - 4);
RenderHelper.right_window_border.renderH(stack, width - RenderHelper.right_window_border.rect_w(), 3, height - 4);
RenderHelper.top_left_window_corner.render(stack, 0, 0);
RenderHelper.top_right_window_corner.render(stack, width - RenderHelper.top_right_window_corner.rect_w(), 0);
if (active) {
if (!initial) {
RenderHelper.tab_left_connection.render(stack, 0, height - RenderHelper.tab_left_connection.rect_h() - 1);
}
RenderHelper.tab_right_connection.render(stack, width - RenderHelper.tab_right_connection.rect_w(), height - RenderHelper.tab_left_connection.rect_h() - 1);
}
}
}
@Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
if (active) {
return true;
}
for (var tab : top_tabs) {
if (tab != this) {
if (tab.active) {
tab.on_close.run();
tab.active = false;
}
}
}
for (var tab : left_tabs) {
if (tab != this) {
if (tab.active) {
tab.on_close.run();
tab.active = false;
}
}
}
for (var tab : right_tabs) {
if (tab != this) {
if (tab.active) {
tab.on_close.run();
tab.active = false;
}
}
}
for (var tab : bottom_tabs) {
if (tab != this) {
if (tab.active) {
tab.on_close.run();
tab.active = false;
}
}
}
active = true;
on_open.run();
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
return true;
}
}
protected final ArrayList<FrameTabPanel> top_tabs = new ArrayList<>();
protected final ArrayList<FrameTabPanel> left_tabs = new ArrayList<>();
protected final ArrayList<FrameTabPanel> right_tabs = new ArrayList<>();
protected final ArrayList<FrameTabPanel> bottom_tabs = new ArrayList<>();
public FrameTabPanel addTab(FrameTabPosition position, Runnable on_open, Runnable on_close) {
var tab = new FrameTabPanel(position, on_open, on_close);
if (top_tabs.size() == 0 && left_tabs.size() == 0 && right_tabs.size() == 0 && bottom_tabs.size() == 0) {
tab.active = true;
}
switch (position) {
case TOP -> top_tabs.add(tab);
case LEFT -> left_tabs.add(tab);
case RIGHT -> right_tabs.add(tab);
case BOTTOM -> bottom_tabs.add(tab);
}
return tab;
}
@Override
protected void performLayout() {
for (int i = 0; i < top_tabs.size(); i++) {
var tab = top_tabs.get(i);
tab.setPos(i * FrameTabPosition.TOP.width, -FrameTabPosition.TOP.height);
tab.initial = i == 0;
}
super.performLayout();
}
protected Component title; protected Component title;
public static final int PADDING = 4;
public static final int PADDING_TOP = 14;
public FramePanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Component title) { public FramePanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Component title) {
super(screen, parent, x, y, width, height); super(screen, parent, x, y, width, height);
this.title = title; this.title = title;
setDockPadding(4, 14, 4, 4); setDockPadding(PADDING, PADDING_TOP, PADDING, PADDING);
} }
protected boolean dragging = false; protected boolean dragging = false;
@ -86,4 +251,8 @@ public class FramePanel extends EditablePanel implements NarratableEntry {
public void updateNarration(NarrationElementOutput narrationElementOutput) { public void updateNarration(NarrationElementOutput narrationElementOutput) {
} }
public void toScreenCenter() {
setPos(screen.width / 2 - (int) (getWidth() / 2), screen.height / 2 - (int) (getHeight() / 2));
}
} }

View File

@ -0,0 +1,65 @@
package ru.dbotthepony.mc.otm.screen.panels;
import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class GridPanel extends EditablePanel {
protected int grid_width;
protected int grid_height;
public GridPanel(
@Nonnull MatteryScreen<?> screen,
@Nullable EditablePanel parent,
float x,
float y,
float width,
float height,
int grid_width,
int grid_height
) {
super(screen, parent, x, y, width, height);
this.grid_width = grid_width;
this.grid_height = grid_height;
}
@Override
protected void performLayout() {
super.performLayout();
float current_x = 0;
float current_y = 0;
float line_y = 0;
int index = 0;
for (int row = 0; row < grid_height; row++) {
for (int column = 0; column < grid_width; column++) {
var child = childAtIndex(index);
if (child == null) {
break;
}
if (child.getVisible()) {
line_y = Math.max(line_y, child.getHeight());
child.setPos(current_x, current_y);
current_x += child.getWidth();
} else {
column--;
}
index++;
}
current_y += line_y;
current_x = 0;
line_y = 0;
if (childAtIndex(index) == null) {
break;
}
}
}
}

View File

@ -24,12 +24,16 @@ public class MatteryWidgetPanel extends EditablePanel {
} }
@Override @Override
protected void innerRenderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) { protected boolean innerRenderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) {
if (is_hovered) { if (is_hovered) {
var tooltips = widget.getTooltip(); var tooltips = widget.getTooltip();
if (tooltips != null) if (tooltips != null) {
screen.renderComponentTooltip(stack, tooltips, (int) mouse_x, (int) mouse_y); screen.renderComponentTooltip(stack, tooltips, (int) mouse_x, (int) mouse_y);
return true;
} }
} }
return false;
}
} }

View File

@ -4,6 +4,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.screen.MatteryScreen; import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -17,27 +18,36 @@ public class MinecraftWidgetPanel<T extends AbstractWidget> extends EditablePane
protected T widget; protected T widget;
private final WidgetFactory<T> factory; private final WidgetFactory<T> factory;
@Nullable
public T getWidget() { public T getWidget() {
return widget; return widget;
} }
public MinecraftWidgetPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, WidgetFactory<T> factory) { public MinecraftWidgetPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, WidgetFactory<T> factory) {
super(screen, parent, x, y, width, height); super(screen, parent, x, y, width, height);
this.widget = factory.create(this);
this.factory = factory; this.factory = factory;
} }
protected void copyValues(T new_widget, T old_widget) { protected void copyValues(@Nonnull T new_widget, @Nonnull T old_widget) {
} }
private void recreate() { private void recreate() {
if (widget == null) {
return;
}
var new_widget = factory.create(this); var new_widget = factory.create(this);
new_widget.visible = getVisible(); new_widget.visible = getVisible();
new_widget.x = (int) parent_x; new_widget.x = (int) parent_x;
new_widget.y = (int) parent_y; new_widget.y = (int) parent_y;
if (widget != null)
copyValues(new_widget, widget); copyValues(new_widget, widget);
widget = new_widget; widget = new_widget;
factorize(widget, true);
} }
@Override @Override
@ -52,11 +62,60 @@ public class MinecraftWidgetPanel<T extends AbstractWidget> extends EditablePane
@Override @Override
protected void visibilityChanges(boolean new_visible, boolean old_visible) { protected void visibilityChanges(boolean new_visible, boolean old_visible) {
if (widget != null)
widget.visible = new_visible; widget.visible = new_visible;
} }
/**
* Override in final classes to define values
*
* @param widget
*/
protected void factorize(T widget, boolean recreation) {
}
@Nonnull
public T getOrCreateWidget() {
if (widget != null)
return widget;
widget = factory.create(this);
widget.visible = getVisible();
factorize(widget, false);
return widget;
}
@Override @Override
protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) { protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) {
widget.render(stack, (int) mouse_x, (int) mouse_y, flag); getOrCreateWidget().render(stack, (int) mouse_x, (int) mouse_y, flag);
}
@Override
protected boolean charTypedInternal(char p_94732_, int p_94733_) {
return getOrCreateWidget().charTyped(p_94732_, p_94733_);
}
@Override
protected boolean keyPressedInternal(int p_94745_, int p_94746_, int p_94747_) {
return getOrCreateWidget().keyPressed(p_94745_, p_94746_, p_94747_);
}
@Override
protected boolean keyReleasedInternal(int p_94750_, int p_94751_, int p_94752_) {
return getOrCreateWidget().keyReleased(p_94750_, p_94751_, p_94752_);
}
@Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
var pos = screenToLocal(mouse_x, mouse_y);
return getOrCreateWidget().mouseClicked(pos.x(), pos.y(), flag);
}
@Override
protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) {
var pos = screenToLocal(mouse_x, mouse_y);
return getOrCreateWidget().mouseReleased(pos.x(), pos.y(), flag);
} }
} }

View File

@ -0,0 +1,171 @@
package ru.dbotthepony.mc.otm.screen.panels;
import com.mojang.blaze3d.vertex.PoseStack;
import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import ru.dbotthepony.mc.otm.screen.RenderHelper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class ScrollBarPanel extends EditablePanel {
public class ScrollBarButtonPanel extends EditablePanel {
public ScrollBarButtonPanel() {
super(ScrollBarPanel.this.screen, ScrollBarPanel.this, 1, 1, 12, 15);
}
private boolean is_scrolling;
public boolean isScrolling() {
return is_scrolling;
}
@Override
protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) {
if (is_scrolling) {
RenderHelper.scroll_bar_button_press.render(stack, 0, 0);
} else if (is_hovered) {
RenderHelper.scroll_bar_button_hover.render(stack, 0, 0);
} else {
RenderHelper.scroll_bar_button.render(stack, 0, 0);
}
}
private double last_mouse_y;
@Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) {
is_scrolling = true;
setIgnoreMouseEventBoundaries(true);
last_mouse_y = mouse_y;
return true;
}
@Override
protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) {
if (is_scrolling) {
is_scrolling = false;
setIgnoreMouseEventBoundaries(false);
scroll = getScroll();
return true;
}
return false;
}
@Override
protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
return ScrollBarPanel.this.mouseScrolledInner(mouse_x, mouse_y, scroll);
}
@Override
protected boolean mouseDraggedInner(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) {
if (is_scrolling) {
var diff = mouse_y - last_mouse_y;
last_mouse_y = mouse_y;
setScrollInternal((float) (scroll + diff / ScrollBarPanel.this.getHeight()));
updateScrollBarPosition();
return true;
}
return false;
}
}
public static final int WIDTH = 14;
public final ScrollBarButtonPanel scroll_button = new ScrollBarButtonPanel();
public Consumer<Float> scroll_callback;
@Nonnull
public Supplier<Float> scroll_multiplier = () -> 0.1f;
public ScrollBarPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float height) {
super(screen, parent, x, y, WIDTH, height);
}
public void setupRowMultiplier(Supplier<Integer> row_supplier) {
scroll_multiplier = () -> {
int rows = row_supplier.get();
if (rows < 1) {
return 0f;
}
return 1f / rows;
};
}
protected float scroll;
protected void onScrolled(float new_scroll, float old_scroll) {
if (scroll_callback != null)
scroll_callback.accept(new_scroll);
}
public float getScroll() {
return scroll < 0 ? 0 : scroll > 1 ? 1 : scroll;
}
public void setScroll(float scroll) {
var previous = this.scroll;
this.scroll = scroll < 0 ? 0 : scroll > 1 ? 1 : scroll;
if (previous != this.scroll) {
onScrolled(this.scroll, previous);
}
}
protected void setScrollInternal(float scroll) {
var previous = getScroll();
this.scroll = scroll;
var current = getScroll();
if (previous != current) {
onScrolled(current, previous);
}
}
public void updateScrollBarPosition() {
scroll_button.setY(1 + (getHeight() - 2 - scroll_button.getHeight()) * getScroll());
}
@Override
protected void performLayout() {
super.performLayout();
updateScrollBarPosition();
}
public void translateScrollValue(int new_max, int old_max) {
if (new_max < 1 || old_max < 1) {
return;
}
scroll = (scroll * old_max) / new_max;
}
public int getScroll(int max_rows) {
if (max_rows <= 1) {
return 0;
}
return (int) Math.floor(getScroll() * (max_rows - 1) + 0.5);
}
// public is for emulating input from outside
@Override
public boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) {
setScrollInternal((float) (this.scroll + scroll * scroll_multiplier.get()));
return true;
}
@Override
protected void innerRender(PoseStack stack, float mouse_x, float mouse_y, float flag) {
RenderHelper.drawScrollBarBackground(stack, 0, 0, getHeight());
}
}

View File

@ -19,7 +19,7 @@ import ru.dbotthepony.mc.otm.screen.RenderHelper;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class SlotPanel<T extends MatterySlot> extends EditablePanel { public class SlotPanel<T extends MatterySlot> extends AbstractSlotPanel {
public final T slot; public final T slot;
public SlotPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, T slot) { public SlotPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, T slot) {
@ -31,9 +31,6 @@ public class SlotPanel<T extends MatterySlot> extends EditablePanel {
this(screen, parent, slot.x, slot.y, 18, 18, slot); this(screen, parent, slot.x, slot.y, 18, 18, slot);
} }
public final RGBAColor SLOT_HIGHLIGHT = new RGBAColor(255, 255, 255, 100);
public final RGBAColor SLOT_HIGHLIGHT_DRAG = new RGBAColor(200, 200, 200, 150);
@Override @Override
protected boolean mouseClickedInner(double mouse_x, double mouse_y, int button) { protected boolean mouseClickedInner(double mouse_x, double mouse_y, int button) {
screen.onSlotClicked(slot, button); screen.onSlotClicked(slot, button);
@ -52,43 +49,10 @@ public class SlotPanel<T extends MatterySlot> extends EditablePanel {
return true; return true;
} }
protected void renderSlotBackground(PoseStack stack, float mouse_x, float mouse_y, float flag) { @Nonnull
RenderHelper.drawRegularSlot(stack, 0, 0); @Override
} protected ItemStack getItemStack() {
return slot.getItem();
protected void renderRegular(PoseStack stack, ItemStack itemstack, String count_override) {
if (!itemstack.isEmpty()) {
RenderSystem.enableDepthTest();
var system_stack = RenderSystem.getModelViewStack();
system_stack.pushPose();
system_stack.translate(parent_x + 1, parent_y + 1, 0);
RenderSystem.applyModelViewMatrix();
// Thanks Mojang
// Very cool
// (for int x, int y, which are then cast into doubles anyway)
screen.getItemRenderer().blitOffset = accumulated_depth - 100; // force item to draw only 50 units "above" background
screen.getItemRenderer().renderAndDecorateItem(Minecraft.getInstance().player, itemstack, 0, 0, (int) (parent_x + parent_y * 1000) /* some kind of indexing ? */);
screen.getItemRenderer().renderGuiItemDecorations(screen.getFont(), itemstack, 0, 0, count_override);
// too big accumulations can lead to Z near clipping issues
accumulate3DHeight(100);
system_stack.popPose();
RenderSystem.applyModelViewMatrix();
}
if (is_hovered) {
screen.hoveredSlot = slot;
stack.pushPose();
stack.translate(0, 0, 101);
RenderHelper.setDrawColor(SLOT_HIGHLIGHT);
RenderHelper.drawRect(stack, 1, 1, getWidth() - 1, getHeight() - 1);
stack.popPose();
}
} }
@Override @Override
@ -130,5 +94,15 @@ public class SlotPanel<T extends MatterySlot> extends EditablePanel {
} }
renderRegular(stack, itemstack, count_override); renderRegular(stack, itemstack, count_override);
if (is_hovered) {
screen.hoveredSlot = slot;
}
}
@Override
protected boolean innerRenderTooltips(PoseStack stack, float mouse_x, float mouse_y, float flag) {
// no op, screen does it for us (completely)
return false;
} }
} }

View File

@ -0,0 +1,27 @@
package ru.dbotthepony.mc.otm.screen.panels;
import net.minecraft.world.item.ItemStack;
import ru.dbotthepony.mc.otm.screen.MatteryScreen;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.Supplier;
public class SupplierSlotPanel extends AbstractSlotPanel {
protected Supplier<ItemStack> stack_getter;
public SupplierSlotPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, float width, float height, Supplier<ItemStack> supplier) {
super(screen, parent, x, y, width, height);
stack_getter = supplier;
}
public SupplierSlotPanel(@Nonnull MatteryScreen<?> screen, @Nullable EditablePanel parent, float x, float y, Supplier<ItemStack> supplier) {
this(screen, parent, x, y, REGULAR_DIMENSIONS, REGULAR_DIMENSIONS, supplier);
}
@Nonnull
@Override
protected ItemStack getItemStack() {
return stack_getter.get();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB