BetterControlsScreen.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. package chylex.bettercontrols.gui;
  2. import chylex.bettercontrols.BetterControlsMod;
  3. import chylex.bettercontrols.config.BetterControlsConfig;
  4. import chylex.bettercontrols.gui.elements.BooleanValueWidget;
  5. import chylex.bettercontrols.gui.elements.CycleButtonWidget;
  6. import chylex.bettercontrols.gui.elements.DiscreteValueSliderWidget;
  7. import chylex.bettercontrols.gui.elements.KeyBindingWidget;
  8. import chylex.bettercontrols.gui.elements.Option;
  9. import chylex.bettercontrols.gui.elements.TextWidget;
  10. import chylex.bettercontrols.input.KeyBindingWithModifier;
  11. import chylex.bettercontrols.input.ModifierKey;
  12. import net.minecraft.client.MinecraftClient;
  13. import net.minecraft.client.gui.Element;
  14. import net.minecraft.client.gui.screen.Screen;
  15. import net.minecraft.client.gui.screen.ScreenTexts;
  16. import net.minecraft.client.gui.screen.options.GameOptionsScreen;
  17. import net.minecraft.client.gui.widget.ButtonWidget;
  18. import net.minecraft.client.options.KeyBinding;
  19. import net.minecraft.client.util.InputUtil;
  20. import net.minecraft.client.util.math.MatrixStack;
  21. import net.minecraft.text.LiteralText;
  22. import net.minecraft.text.Text;
  23. import org.lwjgl.glfw.GLFW;
  24. import java.util.ArrayList;
  25. import java.util.Arrays;
  26. import java.util.List;
  27. import static chylex.bettercontrols.gui.OptionListWidget.COL2_W;
  28. import static chylex.bettercontrols.gui.OptionListWidget.COL4_W;
  29. import static chylex.bettercontrols.gui.OptionListWidget.ROW_WIDTH;
  30. import static chylex.bettercontrols.gui.OptionListWidget.col2;
  31. import static chylex.bettercontrols.gui.OptionListWidget.col4;
  32. import static chylex.bettercontrols.gui.elements.TextWidget.CENTER;
  33. public class BetterControlsScreen extends GameOptionsScreen{
  34. public static final LiteralText TITLE = new LiteralText("Better Controls");
  35. private static final int BOTTOM_PADDING = 3;
  36. private static final int TEXT_PADDING_RIGHT = 4;
  37. private static final int TITLE_MARGIN_TOP = 3;
  38. private static final int ROW_HEIGHT = 22;
  39. // Options
  40. private int generateSprintingOptions(int y, final List<Element> elements){
  41. final BetterControlsConfig cfg = BetterControlsMod.config;
  42. generateKeyBindingWithModifierOption(y, elements, Text.of("Toggle Sprint"), cfg.keyToggleSprint);
  43. y += ROW_HEIGHT;
  44. generateLeftSideText(y, elements, Text.of("Double Tap 'Walk Forwards' To Sprint"));
  45. elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.doubleTapForwardToSprint, value -> cfg.doubleTapForwardToSprint = value));
  46. y += ROW_HEIGHT;
  47. generateLeftSideText(y, elements, Text.of("Resume Sprinting After Hitting Obstacle"));
  48. elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.resumeSprintingAfterHittingObstacle, value -> cfg.resumeSprintingAfterHittingObstacle = value));
  49. y += ROW_HEIGHT;
  50. return y;
  51. }
  52. private int generateSneakingOptions(int y, final List<Element> elements){
  53. final BetterControlsConfig cfg = BetterControlsMod.config;
  54. generateKeyBindingWithModifierOption(y, elements, Text.of("Toggle Sneak"), cfg.keyToggleSneak);
  55. y += ROW_HEIGHT;
  56. generateLeftSideText(y, elements, Text.of("Move Camera Smoothly"));
  57. elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.sneakingMovesCameraSmoothly, value -> cfg.sneakingMovesCameraSmoothly = value));
  58. y += ROW_HEIGHT;
  59. return y;
  60. }
  61. @SuppressWarnings({ "AutoBoxing", "AutoUnboxing" })
  62. private int generateFlightOptions(int y, final List<Element> elements){
  63. final BetterControlsConfig cfg = BetterControlsMod.config;
  64. final List<Option<Float>> flightSpeedOptions = Arrays.asList(
  65. new Option<>(Float.valueOf(0.25F), Text.of("0.25x")),
  66. new Option<>(Float.valueOf(0.50F), Text.of("0.5x")),
  67. new Option<>(Float.valueOf(0.75F), Text.of("0.75x")),
  68. new Option<>(Float.valueOf(1.00F), Text.of("1x")),
  69. new Option<>(Float.valueOf(1.50F), Text.of("1.5x")),
  70. new Option<>(Float.valueOf(2.00F), Text.of("2x")),
  71. new Option<>(Float.valueOf(3.00F), Text.of("3x")),
  72. new Option<>(Float.valueOf(4.00F), Text.of("4x")),
  73. new Option<>(Float.valueOf(6.00F), Text.of("6x")),
  74. new Option<>(Float.valueOf(8.00F), Text.of("8x"))
  75. );
  76. generateKeyBindingWithModifierOption(y, elements, Text.of("Toggle Flight (Creative)"), cfg.keyToggleFlight);
  77. y += ROW_HEIGHT;
  78. generateLeftSideText(y, elements, Text.of("Fly On Ground (Creative Mode)"));
  79. elements.add(new BooleanValueWidget(col2(1), y, COL2_W, cfg.flyOnGroundInCreative, value -> cfg.flyOnGroundInCreative = value));
  80. y += ROW_HEIGHT * 4 / 3;
  81. generateLeftSideText(y, elements, Text.of("Speed Multiplier (Creative)"));
  82. elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpCreativeDefault, value -> cfg.flightSpeedMpCreativeDefault = value));
  83. y += ROW_HEIGHT;
  84. generateLeftSideText(y, elements, Text.of("Speed Multiplier (Creative + Sprinting)"));
  85. elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpCreativeSprinting, value -> cfg.flightSpeedMpCreativeSprinting = value));
  86. y += ROW_HEIGHT;
  87. generateLeftSideText(y, elements, Text.of("Speed Multiplier (Spectator)"));
  88. elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpSpectatorDefault, value -> cfg.flightSpeedMpSpectatorDefault = value));
  89. y += ROW_HEIGHT;
  90. generateLeftSideText(y, elements, Text.of("Speed Multiplier (Spectator + Sprinting)"));
  91. elements.add(new DiscreteValueSliderWidget<>(col2(1), y, COL2_W, flightSpeedOptions, cfg.flightSpeedMpSpectatorSprinting, value -> cfg.flightSpeedMpSpectatorSprinting = value));
  92. y += ROW_HEIGHT;
  93. return y;
  94. }
  95. private int generateMiscellaneousOptions(int y, final List<Element> elements){
  96. final BetterControlsConfig cfg = BetterControlsMod.config;
  97. generateKeyBindingWithModifierOption(y, elements, Text.of("Toggle Walk Forwards"), cfg.keyToggleWalkForward);
  98. y += ROW_HEIGHT;
  99. generateKeyBindingWithModifierOption(y, elements, Text.of("Toggle Jump"), cfg.keyToggleJump);
  100. y += ROW_HEIGHT * 4 / 3;
  101. generateKeyBindingWithModifierOption(y, elements, Text.of("Open Better Controls Menu"), cfg.keyOpenMenu);
  102. y += ROW_HEIGHT;
  103. return y;
  104. }
  105. // Helpers
  106. private static final List<Option<ModifierKey>> MODIFIER_OPTIONS = Arrays.asList(
  107. new Option<>(null, Text.of("(No Modifier)")),
  108. new Option<>(ModifierKey.CONTROL, Text.of("Control")),
  109. new Option<>(ModifierKey.SHIFT, Text.of("Shift")),
  110. new Option<>(ModifierKey.ALT, Text.of("Alt"))
  111. );
  112. private void generateKeyBindingWithModifierOption(final int y, final List<Element> elements, final Text text, final KeyBindingWithModifier binding){
  113. final CycleButtonWidget<ModifierKey> modifierButton = new CycleButtonWidget<>(col4(2), y, COL4_W, MODIFIER_OPTIONS, binding.getModifier(), binding::setModifier);
  114. final KeyBindingWidget bindingButton = new KeyBindingWidget(col4(3), y, COL4_W, binding, this::startEditingKeyBinding);
  115. bindingButton.linkButtonToBoundState(modifierButton);
  116. generateLeftSideText(y, elements, text);
  117. elements.add(modifierButton);
  118. elements.add(bindingButton);
  119. allKeyBindings.add(bindingButton);
  120. }
  121. private static void generateLeftSideText(final int y, final List<Element> elements, final Text text){
  122. elements.add(new TextWidget(col2(0), y, COL2_W - TEXT_PADDING_RIGHT, text));
  123. }
  124. // Instance
  125. private OptionListWidget optionsWidget;
  126. private KeyBindingWidget editingKeyBinding;
  127. private final List<KeyBindingWidget> allKeyBindings = new ArrayList<>();
  128. public BetterControlsScreen(final Screen parentScreen){
  129. super(parentScreen, MinecraftClient.getInstance().options, TITLE);
  130. }
  131. @Override
  132. public void init(){
  133. allKeyBindings.clear();
  134. final List<Element> elements = new ArrayList<>();
  135. int y = 0;
  136. elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, Text.of("Sprinting"), CENTER));
  137. y = generateSprintingOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
  138. elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, Text.of("Sneaking"), CENTER));
  139. y = generateSneakingOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
  140. elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, Text.of("Flying"), CENTER));
  141. y = generateFlightOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
  142. elements.add(new TextWidget(0, y, ROW_WIDTH, ROW_HEIGHT, Text.of("Miscellaneous"), CENTER));
  143. y = generateMiscellaneousOptions(y + ROW_HEIGHT, elements) + TITLE_MARGIN_TOP;
  144. addButton(new ButtonWidget(width / 2 - 99, height - 29, 200, 20, ScreenTexts.DONE, btn -> client.openScreen(parent)));
  145. addChild(optionsWidget = new OptionListWidget(21, height - 32, width, height, elements, y - TITLE_MARGIN_TOP + BOTTOM_PADDING));
  146. }
  147. @Override
  148. public void removed(){
  149. BetterControlsMod.config.save();
  150. }
  151. @Override
  152. public void render(final MatrixStack matrices, final int mouseX, final int mouseY, final float delta){
  153. renderBackground(matrices);
  154. optionsWidget.render(matrices, mouseX, mouseY, delta);
  155. drawCenteredText(matrices, textRenderer, title, width / 2, 8, (255 << 16) | (255 << 8) | 255);
  156. super.render(matrices, mouseX, mouseY, delta);
  157. }
  158. private void startEditingKeyBinding(final KeyBindingWidget widget){
  159. if (editingKeyBinding != null){
  160. editingKeyBinding.stopEditing();
  161. }
  162. editingKeyBinding = widget;
  163. }
  164. @Override
  165. public boolean mouseClicked(final double mouseX, final double mouseY, final int button){
  166. if (editingKeyBinding != null){
  167. editingKeyBinding.bindAndStopEditing(InputUtil.Type.MOUSE.createFromCode(button));
  168. onKeyBindingEditingFinished();
  169. return true;
  170. }
  171. else{
  172. return super.mouseClicked(mouseX, mouseY, button);
  173. }
  174. }
  175. @Override
  176. public boolean keyPressed(final int keyCode, final int scanCode, final int modifiers){
  177. if (editingKeyBinding != null){
  178. if (keyCode == GLFW.GLFW_KEY_ESCAPE){
  179. editingKeyBinding.bindAndStopEditing(InputUtil.UNKNOWN_KEY);
  180. }
  181. else{
  182. editingKeyBinding.bindAndStopEditing(InputUtil.fromKeyCode(keyCode, scanCode));
  183. }
  184. onKeyBindingEditingFinished();
  185. return true;
  186. }
  187. else{
  188. return super.keyPressed(keyCode, scanCode, modifiers);
  189. }
  190. }
  191. private void onKeyBindingEditingFinished(){
  192. editingKeyBinding = null;
  193. KeyBinding.updateKeysByCode();
  194. for(final KeyBindingWidget widget : allKeyBindings){
  195. widget.updateKeyBindingText();
  196. }
  197. }
  198. }