Skip to content

Commit

Permalink
Pagination for 1.6.4 controls screen (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
thecatcore committed Jul 2, 2024
1 parent 052b567 commit 88808f6
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - 2024 Legacy Fabric
* Copyright (c) 2016 - 2022 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.legacyfabric.fabric.impl.client.keybinding;

public interface ControlsScreenExtensions {
void fabric_nextPage();

void fabric_previousPage();

int fabric_currentPage();

boolean fabric_isButtonVisible(FabricControlsScreenComponents.Type type);

boolean fabric_isButtonEnabled(FabricControlsScreenComponents.Type type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2020 - 2024 Legacy Fabric
* Copyright (c) 2016 - 2022 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.legacyfabric.fabric.impl.client.keybinding;

import java.util.function.Consumer;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;

import net.legacyfabric.fabric.api.util.Identifier;

public class FabricControlsScreenComponents {
private static final Identifier BUTTON_TEX = new Identifier("legacy-fabric", "textures/gui/creative_buttons.png");
public static final int AMOUNT_PER_PAGE = 14;

public static class ControlsButtonWidget extends ButtonWidget {
ControlsScreenExtensions extensions;
ControlsOptionsScreen gui;
Type type;

public ControlsButtonWidget(int x, int y, Type type, ControlsScreenExtensions extensions) {
super(1000 + type.ordinal(), x, y, 20, 20, type.text);
this.extensions = extensions;
this.type = type;
this.gui = (ControlsOptionsScreen) extensions;
}

public void click() {
if (this.active) {
this.type.clickConsumer.accept(this.extensions);
}
}

@Override
public boolean isMouseOver(MinecraftClient client, int mouseX, int mouseY) {
return super.isMouseOver(client, mouseX, mouseY);
}

@Override
public void mouseDragged(MinecraftClient client, int mouseX, int mouseY) {
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
this.visible = extensions.fabric_isButtonVisible(type);
this.active = extensions.fabric_isButtonEnabled(type);
}
}

public enum Type {
NEXT(">", ControlsScreenExtensions::fabric_nextPage),
PREVIOUS("<", ControlsScreenExtensions::fabric_previousPage);

final String text;
final Consumer<ControlsScreenExtensions> clickConsumer;

Type(String text, Consumer<ControlsScreenExtensions> clickConsumer) {
this.text = text;
this.clickConsumer = clickConsumer;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright (c) 2020 - 2024 Legacy Fabric
* Copyright (c) 2016 - 2022 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.legacyfabric.fabric.mixin.client.keybinding;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.options.ControlsOptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.OptionButtonWidget;
import net.minecraft.client.option.GameOptions;

import net.legacyfabric.fabric.impl.client.keybinding.ControlsScreenExtensions;
import net.legacyfabric.fabric.impl.client.keybinding.FabricControlsScreenComponents;

@Mixin(ControlsOptionsScreen.class)
public class ControlsOptionsScreenMixin extends Screen implements ControlsScreenExtensions {
@Shadow
private GameOptions options;

private static int fabric_currentPage = 0;

private int fabric_getPageOffset(int page) {
switch (page) {
case 0:
return 0;
case 1:
return FabricControlsScreenComponents.AMOUNT_PER_PAGE;
default:
return FabricControlsScreenComponents.AMOUNT_PER_PAGE + ((page - 1) * FabricControlsScreenComponents.AMOUNT_PER_PAGE);
}
}

private int fabric_getOffsetPage(int offset) {
if (offset < FabricControlsScreenComponents.AMOUNT_PER_PAGE) {
return 0;
} else {
return 1 + ((offset - FabricControlsScreenComponents.AMOUNT_PER_PAGE) / FabricControlsScreenComponents.AMOUNT_PER_PAGE);
}
}

@Override
public boolean fabric_isButtonVisible(FabricControlsScreenComponents.Type type) {
return this.options.allKeys.length > FabricControlsScreenComponents.AMOUNT_PER_PAGE;
}

@Override
public void fabric_nextPage() {
if (fabric_getPageOffset(fabric_currentPage + 1) >= this.options.allKeys.length) {
return;
}

fabric_currentPage++;
fabric_updateSelection();
}

@Override
public void fabric_previousPage() {
if (fabric_currentPage == 0) {
return;
}

fabric_currentPage--;
fabric_updateSelection();
}

@Override
public int fabric_currentPage() {
return fabric_currentPage;
}

@Override
public boolean fabric_isButtonEnabled(FabricControlsScreenComponents.Type type) {
if (type == FabricControlsScreenComponents.Type.NEXT) {
return !(fabric_getPageOffset(fabric_currentPage + 1) >= this.options.allKeys.length);
}

if (type == FabricControlsScreenComponents.Type.PREVIOUS) {
return fabric_currentPage != 0;
}

return false;
}

@Inject(at = @At("HEAD"), method = "buttonClicked", cancellable = true)
private void interceptClick(ButtonWidget button, CallbackInfo ci) {
if (button instanceof FabricControlsScreenComponents.ControlsButtonWidget) {
((FabricControlsScreenComponents.ControlsButtonWidget) button).click();
ci.cancel();
}
}

private boolean fabric_isControlVisible(int id) {
return fabric_currentPage == fabric_getOffsetPage(id);
}

private void fabric_updateSelection() {
for (Object widget : this.buttons) {
if (widget instanceof OptionButtonWidget) {
((OptionButtonWidget) widget).visible = fabric_isControlVisible(((ButtonWidget) widget).id);
}
}
}

@ModifyArg(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/widget/OptionButtonWidget;<init>(IIIIILjava/lang/String;)V"), index = 2)
private int modifyControlY(int y) {
int temp = y - (this.height / 6);
int heightOffset = temp / 24;
return this.height / 6 + 24 * (heightOffset % 7);
}

@Inject(method = "init", at = @At("RETURN"))
private void init(CallbackInfo info) {
fabric_updateSelection();

buttons.add(new FabricControlsScreenComponents.ControlsButtonWidget(this.width / 2 + 100, this.height / 6 + 168, FabricControlsScreenComponents.Type.NEXT, this));
buttons.add(new FabricControlsScreenComponents.ControlsButtonWidget(this.width / 2 - 120, this.height / 6 + 168, FabricControlsScreenComponents.Type.PREVIOUS, this));
}

@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/options/ControlsOptionsScreen;drawWithShadow(Lnet/minecraft/client/font/TextRenderer;Ljava/lang/String;III)V"))
private void modifyLabelPos(ControlsOptionsScreen instance, TextRenderer textRenderer, String text, int x, int y, int color, Operation<Void> original, @Local(index = 5) int id) {
if (fabric_isControlVisible(id)) {
int temp = y - (this.height / 6);
int heightOffset = temp / 24;
y = this.height / 6 + 24 * (heightOffset % 7) + 7;
original.call(instance, textRenderer, text, x, y, color);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"depends": {
"minecraft": "${minecraft_version}"
},
"mixins": [],
"mixins": [
"legacy-fabric-keybinding-api-v1.mixins.json"
],
"description": "Hooks that help adding keybindings",
"custom": {
"modmenu": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"required": true,
"package": "net.legacyfabric.fabric.mixin.client.keybinding",
"compatibilityLevel": "JAVA_8",
"client": [
"ControlsOptionsScreenMixin"
],
"injectors": {
"defaultRequire": 1
}
}

0 comments on commit 88808f6

Please sign in to comment.