]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/commitdiff
Fully support keyboard nav in gui
authorIrtimaled <irtimaled@gmail.com>
Thu, 21 May 2020 22:33:50 +0000 (15:33 -0700)
committerIrtimaled <irtimaled@gmail.com>
Sat, 23 May 2020 07:00:30 +0000 (00:00 -0700)
21 files changed:
src/main/java/com/irtimaled/bbor/client/gui/AbstractButton.java
src/main/java/com/irtimaled/bbor/client/gui/AbstractControl.java
src/main/java/com/irtimaled/bbor/client/gui/AbstractSlider.java
src/main/java/com/irtimaled/bbor/client/gui/BoolButton.java
src/main/java/com/irtimaled/bbor/client/gui/ControlList.java
src/main/java/com/irtimaled/bbor/client/gui/ControlListEntry.java
src/main/java/com/irtimaled/bbor/client/gui/ControlListSection.java
src/main/java/com/irtimaled/bbor/client/gui/CreateControl.java
src/main/java/com/irtimaled/bbor/client/gui/IControl.java
src/main/java/com/irtimaled/bbor/client/gui/IControlSet.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/gui/IFocusableControl.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/gui/IntSettingSlider.java
src/main/java/com/irtimaled/bbor/client/gui/ListHelper.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/gui/ListScreen.java
src/main/java/com/irtimaled/bbor/client/gui/LoadSavesScreen.java
src/main/java/com/irtimaled/bbor/client/gui/MaxYSettingSlider.java
src/main/java/com/irtimaled/bbor/client/gui/SearchField.java
src/main/java/com/irtimaled/bbor/client/gui/SelectableControlList.java [new file with mode: 0644]
src/main/java/com/irtimaled/bbor/client/gui/SettingsScreen.java
src/main/java/com/irtimaled/bbor/client/gui/WorldSaveRow.java
src/main/java/com/irtimaled/bbor/mixin/client/gui/MixinGuiOptions.java

index 1ceed2ea688677f4611868004812fc6bf0ef0fea..5fd816af86a63429a8b74a57f5ceb6297108aae8 100644 (file)
@@ -1,30 +1,38 @@
 package com.irtimaled.bbor.client.gui;
 
+import net.minecraft.client.Minecraft;
+
 abstract class AbstractButton extends AbstractControl {
     AbstractButton(int x, int y, int width, String name) {
         super(x, y, width, name);
     }
 
-    AbstractButton(int x, int y, int width, String name, boolean enabled) {
-        this(x, y, width, name);
+    AbstractButton(int width, String name, boolean enabled) {
+        this(0, 0, width, name);
         this.active = enabled;
     }
 
-    @Override
-    protected int getYImage(boolean p_getHoverState_1_) {
-        return getState();
-    }
-
-    protected int getState() {
-        return this.active ? this.isHovered ? 2 : 1 : 0;
-    }
-
     @Override
     public void onClick(double mouseX, double mouseY) {
         super.onClick(mouseX, mouseY);
         onPressed();
     }
 
+    @Override
+    public boolean keyPressed(int key, int scanCode, int modifiers) {
+        if (this.active && this.visible) {
+            if (key != 257 && key != 32 && key != 335) {
+                return false;
+            } else {
+                this.playDownSound(Minecraft.getInstance().getSoundHandler());
+                this.onPressed();
+                return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
     protected abstract void onPressed();
 }
 
index 839e280d6ba544bb46dfde4d0f593a8de4411944..6201d6f5dfba653b31ab3015e57b9e48f5ac0108 100644 (file)
@@ -19,22 +19,18 @@ abstract class AbstractControl extends Widget implements IControl {
         super.render(mouseX, mouseY, 0f);
     }
 
-    @Override
     public void setX(int x) {
         super.x = x;
     }
 
-    @Override
     public void setY(int y) {
         super.y = y;
     }
 
-    @Override
     public int getControlHeight() {
         return this.height + PADDING;
     }
 
-    @Override
     public int getControlWidth() {
         return this.width + PADDING;
     }
@@ -48,24 +44,23 @@ abstract class AbstractControl extends Widget implements IControl {
     }
 
     @Override
-    public void setVisible(boolean visible) {
-        this.visible = visible;
-    }
-
-    @Override
-    public boolean getVisible() {
+    public boolean isVisible() {
         return this.visible;
     }
 
-    @Override
     public void filter(String lowerValue) {
         String lowerString = this.getMessage().toLowerCase();
-        this.setVisible(lowerValue.equals("") ||
+        this.visible = lowerValue.equals("") ||
                 lowerString.startsWith(lowerValue) ||
-                lowerString.contains(" " + lowerValue));
+                lowerString.contains(" " + lowerValue);
     }
 
     void drawRectangle(int left, int top, int right, int bottom, Color color) {
         fill(left, top, right, bottom, color.getRGB());
     }
+
+    @Override
+    public void clearFocus() {
+        this.setFocused(false);
+    }
 }
index d16d3ca9fea6d13464491d9b666aea51649d653e..eaa5f6066d18f807d3ace4f943e79c72450e6985 100644 (file)
@@ -1,43 +1,50 @@
 package com.irtimaled.bbor.client.gui;
 
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.audio.SoundHandler;
 import net.minecraft.util.math.MathHelper;
 import org.lwjgl.opengl.GL11;
 
 abstract class AbstractSlider extends AbstractControl {
-    double progress;
-    private boolean isDragging;
+    private final int optionCount;
+    private final int total;
+    int position = 0;
 
-    AbstractSlider(int x, int y, int width) {
-        super(x, y, width, "");
+    AbstractSlider(int width, int optionCount) {
+        super(0, 0, width, "");
+        this.optionCount = optionCount;
+        total = this.width - 8;
     }
 
     @Override
     protected void renderBackground(int mouseX, int mouseY) {
         this.minecraft.getTextureManager().bindTexture(WIDGETS_LOCATION);
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-        if(isDragging) {
-            changeProgress(mouseX);
-        }
+        int hoverState = super.getYImage(this.isHovered());
+        this.blit(this.x + (int) getProgressPercentage(), this.y, 0, 46 + hoverState * 20, 4, this.height);
+        this.blit(this.x + (int) getProgressPercentage() + 4, this.y, 196, 46 + hoverState * 20, 4, 20);
+    }
 
-        int hoverState = super.getYImage(this.isHovered);
-        this.blit(this.x + (int) (this.progress * (double) (this.width - 8)), this.y, 0, 46 + hoverState * 20, 4, this.height);
-        this.blit(this.x + (int) (this.progress * (double) (this.width - 8)) + 4, this.y, 196, 46 + hoverState * 20, 4, 20);
+    private double getProgressPercentage() {
+        return (this.position / (double) this.optionCount) * (double) total;
     }
 
-    boolean setProgress(double progress) {
-        progress = MathHelper.clamp(progress, 0d, 1d);
-        if (this.progress == progress) return false;
+    private void changeProgress(double mouseX) {
+        double progress = (mouseX - (double) (this.x + 4)) / (double) total;
+        setPosition((int) (progress * optionCount));
+    }
 
-        this.progress = progress;
-        return true;
+    protected int getPosition() {
+        return position;
     }
 
-    private void changeProgress(double mouseX) {
-        double progress = (mouseX - (double) (this.x + 4)) / (double) (this.width - 8);
-        if (setProgress(progress)) {
-            onProgressChanged();
-        }
-        updateText();
+    protected boolean setPosition(int position) {
+        position = MathHelper.clamp(position, 0, optionCount);
+        if (this.position == position) return false;
+
+        this.position = position;
+        onProgressChanged();
+        return true;
     }
 
     @Override
@@ -53,15 +60,23 @@ abstract class AbstractSlider extends AbstractControl {
     @Override
     public void onClick(double mouseX, double mouseY) {
         changeProgress(mouseX);
-        isDragging = true;
     }
 
+    protected abstract void onProgressChanged();
+
     @Override
-    public void onRelease(double mouseX, double mouseY) {
-        this.isDragging = false;
+    public boolean keyPressed(int key, int scanCode, int modifiers) {
+        if (key != 262 && key != 263) return false;
+        int position = getPosition();
+        return key == 263 ? setPosition(position - 1) : setPosition(position + 1);
     }
 
-    protected abstract void updateText();
+    @Override
+    public void playDownSound(SoundHandler soundHandler) {
+    }
 
-    protected abstract void onProgressChanged();
+    @Override
+    public void onRelease(double mouseX, double mouseY) {
+        super.playDownSound(Minecraft.getInstance().getSoundHandler());
+    }
 }
index f61e5dbb8bfad3ff6d361d80da5b7eb58c198955..f7a0ab14041630b36e7306325f0cdb549c034eb7 100644 (file)
@@ -4,28 +4,15 @@ import com.irtimaled.bbor.client.config.ColorHelper;
 import com.irtimaled.bbor.client.config.ConfigManager;
 
 public abstract class BoolButton extends AbstractButton {
-    private boolean value;
-
     BoolButton(int width, String label, boolean enabled) {
-        super(0, 0, width, label, enabled);
+        super(width, label, enabled);
     }
 
     BoolButton(int width, String label) {
         super(0, 0, width, label);
     }
 
-    @Override
-    protected int getState() {
-        return active ? super.getState() : 0;
-    }
-
-    protected boolean getValue() {
-        return this.value;
-    }
-
-    protected void setValue(boolean value) {
-        this.value = value;
-    }
+    protected abstract boolean getValue();
 
     @Override
     protected void renderBackground(int mouseX, int mouseY) {
index 00f9d81535066a7378edc1c6cae52c4d5635560e..d15d97135a771929fdd96ba6bae573c2b70e3ffc 100644 (file)
@@ -4,34 +4,32 @@ import com.irtimaled.bbor.client.renderers.Renderer;
 import com.mojang.blaze3d.platform.GLX;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.AbstractGui;
-import net.minecraft.client.gui.FocusableGui;
-import net.minecraft.client.gui.IGuiEventListener;
 import net.minecraft.util.math.MathHelper;
 import org.lwjgl.opengl.GL11;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
-public class ControlList extends FocusableGui {
-    private static final int CONTROLS_WIDTH = 310;
+public class ControlList extends AbstractGui implements IControlSet {
+    public static final int CONTROLS_WIDTH = 310;
+    protected static final int PADDING = 8;
+
+    protected final int listLeft;
+    protected final List<ControlListEntry> entries = new ArrayList<>();
     private final int scrollBarLeft;
     private final int listHeight;
-    private final int listLeft;
-    private final int listRight;
     private final Minecraft minecraft;
-    private final List<ControlListEntry> entries = new ArrayList<>();
     private final int width;
     private final int height;
     private final int top;
     private final int bottom;
 
-    private int contentHeight = 8;
-    private int selectedElement;
+    protected int contentHeight = PADDING;
     private double amountScrolled;
     private boolean clickedScrollbar;
-    private boolean showSelectionBox;
     private boolean transparentBackground;
+    private IControl focused;
+    private boolean isDragging;
 
     ControlList(int width, int height, int top, int bottom) {
         this.minecraft = Minecraft.getInstance();
@@ -42,12 +40,9 @@ public class ControlList extends FocusableGui {
         this.bottom = bottom;
         this.listHeight = bottom - top;
         this.listLeft = width / 2 - CONTROLS_WIDTH / 2;
-        this.listRight = this.listLeft + CONTROLS_WIDTH;
-        this.selectedElement = -1;
     }
 
     void add(ControlListEntry entry) {
-        entry.list = this;
         entry.index = entries.size();
         addEntry(entry);
     }
@@ -57,18 +52,18 @@ public class ControlList extends FocusableGui {
         this.contentHeight += entry.getControlHeight();
     }
 
-    ControlListEntry getSelectedEntry() {
-        return this.selectedElement >= 0 && this.selectedElement < this.entries.size() ? this.entries.get(this.selectedElement) : null;
-    }
-
-    void filter(String lowerValue) {
+    public void filter(String lowerValue) {
         int height = 0;
-        for (IControl entry : entries) {
+
+        for (ControlListEntry entry : entries) {
             entry.filter(lowerValue);
-            if (entry.getVisible())
+            if (entry.isVisible()) {
                 height += entry.getControlHeight();
+            } else if (entry == focused) {
+                focused = null;
+            }
         }
-        this.contentHeight = height + 8;
+        this.contentHeight = height + PADDING;
     }
 
     void close() {
@@ -78,43 +73,47 @@ public class ControlList extends FocusableGui {
     @Override
     public boolean mouseClicked(double mouseX, double mouseY, int button) {
         this.clickedScrollbar = button == 0 && mouseX >= (double) this.scrollBarLeft;
-        if (mouseY >= (double) this.top && mouseY <= (double) this.bottom) {
-            ControlListEntry entry = this.getEntryAt(mouseX, mouseY);
-            if (entry != null && entry.mouseClicked(mouseX, mouseY, button)) {
-                this.setDragging(true);
-                this.setSelectedIndex(entry.index);
-                return true;
-            } else {
-                return this.clickedScrollbar;
-            }
-        } else {
-            return false;
-        }
+        return isMouseOver(mouseX, mouseY) &&
+                (IControlSet.super.mouseClicked(mouseX, mouseY, button) ||
+                        this.clickedScrollbar);
     }
 
-    void setSelectedIndex(int index) {
-        this.selectedElement = index;
+    @Override
+    public boolean isMouseOver(double mouseX, double mouseY) {
+        return mouseY >= (double) this.top && mouseY <= (double) this.bottom;
     }
 
-    private ControlListEntry getEntryAt(double mouseX, double mouseY) {
-        if (mouseX >= listLeft && mouseX <= listRight) {
-            for (ControlListEntry entry : entries) {
-                if (!entry.getVisible()) continue;
+    @Override
+    public boolean changeFocus(boolean moveForward) {
+        boolean newControlFocused = IControlSet.super.changeFocus(moveForward);
+        if (newControlFocused) {
+            this.ensureVisible((ControlListEntry) this.getFocused());
+        }
 
-                int top = entry.getY();
-                int bottom = top + entry.getControlHeight();
-                if (mouseY >= top && mouseY <= bottom)
-                    return entry;
-            }
+        return newControlFocused;
+    }
+
+    private void ensureVisible(ControlListEntry control) {
+        int controlTop = control.getControlTop();
+        int controlHeight = control.getControlHeight();
+        int distanceAboveTop = this.top - controlTop;
+        if (distanceAboveTop > 0) {
+            this.amountScrolled -= Math.max(controlHeight, distanceAboveTop + PADDING);
+            return;
+        }
+
+        int distanceBelowBottom = controlTop + controlHeight - this.bottom;
+        if (distanceBelowBottom > 0) {
+            this.amountScrolled += Math.max(controlHeight, distanceBelowBottom + PADDING);
         }
-        return null;
     }
 
     @Override
     public boolean mouseDragged(double mouseX, double mouseY, int button, double p_mouseDragged_6_, double p_mouseDragged_8_) {
-        if (super.mouseDragged(mouseX, mouseY, button, p_mouseDragged_6_, p_mouseDragged_8_)) {
+        if (IControlSet.super.mouseDragged(mouseX, mouseY, button, p_mouseDragged_6_, p_mouseDragged_8_)) {
             return true;
-        } else if (button == 0 && this.clickedScrollbar) {
+        }
+        if (button == 0 && this.clickedScrollbar) {
             if (mouseY < (double) this.top) {
                 this.amountScrolled = 0.0D;
             } else if (mouseY > (double) this.bottom) {
@@ -134,9 +133,8 @@ public class ControlList extends FocusableGui {
             }
 
             return true;
-        } else {
-            return false;
         }
+        return false;
     }
 
     private int getMaxScroll() {
@@ -146,13 +144,7 @@ public class ControlList extends FocusableGui {
     private int getScrollBarHeight() {
         return MathHelper.clamp((int) ((float) (this.listHeight * this.listHeight) / (float) this.contentHeight),
                 32,
-                this.listHeight - 8);
-    }
-
-    @Override
-    public boolean mouseReleased(double mouseX, double mouseY, int button) {
-        this.entries.forEach(entry -> entry.mouseReleased(mouseX, mouseY, button));
-        return false;
+                this.listHeight - PADDING);
     }
 
     @Override
@@ -168,7 +160,7 @@ public class ControlList extends FocusableGui {
         GL11.glDisable(GL11.GL_FOG);
         if (!transparentBackground) drawListBackground();
 
-        int listTop = this.top + 8 - (int) this.amountScrolled;
+        int listTop = this.top + PADDING - (int) this.amountScrolled;
 
         drawEntries(mouseX, mouseY, listTop);
 
@@ -207,37 +199,21 @@ public class ControlList extends FocusableGui {
 
     private void drawEntries(int mouseX, int mouseY, int top) {
         for (ControlListEntry entry : this.entries) {
-            if (!entry.getVisible()) continue;
+            if (!entry.isVisible()) continue;
 
             entry.setX(this.listLeft);
             entry.setY(top);
 
             int height = entry.getControlHeight();
-
-            if (this.showSelectionBox && this.selectedElement == entry.index) {
-                GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
-                GL11.glDisable(GL11.GL_TEXTURE_2D);
-                Renderer.startTextured()
-                        .setAlpha(255)
-                        .setColor(128, 128, 128)
-                        .addPoint((double) this.listLeft - 2, (double) (top + height) - 2, 0.0D, 0.0D, 1.0D)
-                        .addPoint((double) this.listRight + 2, (double) (top + height) - 2, 0.0D, 1.0D, 1.0D)
-                        .addPoint((double) this.listRight + 2, top - 2, 0.0D, 1.0D, 0.0D)
-                        .addPoint((double) this.listLeft - 2, top - 2, 0.0D, 0.0D, 0.0D)
-                        .setColor(0, 0, 0)
-                        .addPoint(this.listLeft - 1, (double) (top + height) - 3, 0.0D, 0.0D, 1.0D)
-                        .addPoint(this.listRight + 1, (double) (top + height) - 3, 0.0D, 1.0D, 1.0D)
-                        .addPoint(this.listRight + 1, top - 1, 0.0D, 1.0D, 0.0D)
-                        .addPoint(this.listLeft - 1, top - 1, 0.0D, 0.0D, 0.0D)
-                        .render();
-                GL11.glEnable(GL11.GL_TEXTURE_2D);
-            }
-
-            entry.render(mouseX, mouseY);
-            top += entry.getControlHeight();
+            drawEntry(mouseX, mouseY, top, entry, height);
+            top += height;
         }
     }
 
+    protected void drawEntry(int mouseX, int mouseY, int top, ControlListEntry entry, int height) {
+        entry.render(mouseX, mouseY);
+    }
+
     private void overlayBackground(int top, int bottom) {
         this.minecraft.getTextureManager().bindTexture(AbstractGui.BACKGROUND_LOCATION);
         GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
@@ -302,21 +278,37 @@ public class ControlList extends FocusableGui {
                 .render();
     }
 
-    @Override
-    public List<? extends IGuiEventListener> children() {
-        return Collections.emptyList();
-    }
-
     ControlList section(String title, CreateControl... createControls) {
         this.add(new ControlListSection(title, createControls));
         return this;
     }
 
-    void showSelectionBox() {
-        this.showSelectionBox = true;
-    }
-
     void setTransparentBackground() {
         this.transparentBackground = true;
     }
+
+    @Override
+    public List<? extends IControl> controls() {
+        return entries;
+    }
+
+    @Override
+    public IControl getFocused() {
+        return focused;
+    }
+
+    @Override
+    public void setFocused(IControl control) {
+        this.focused = control;
+    }
+
+    @Override
+    public boolean isDragging() {
+        return isDragging;
+    }
+
+    @Override
+    public void setDragging(boolean dragging) {
+        this.isDragging = dragging;
+    }
 }
index 1521bfe459ee6bfd587b89516307ad186b9011d3..231b097cdcbda3d93daab9eb615a1f030504cfd0 100644 (file)
@@ -2,15 +2,16 @@ package com.irtimaled.bbor.client.gui;
 
 public abstract class ControlListEntry implements IControl {
     int index;
-    ControlList list;
     private int x;
     private int y;
     private boolean visible = true;
 
-    public void close() { }
+    public void close() {
+    }
 
-    @Override
-    public int getControlHeight() { return 24; }
+    public int getControlHeight() {
+        return 24;
+    }
 
     public int getX() {
         return x;
@@ -20,23 +21,29 @@ public abstract class ControlListEntry implements IControl {
         return y;
     }
 
-    @Override
     public void setX(int x) {
         this.x = x;
     }
 
-    @Override
     public void setY(int y) {
         this.y = y;
     }
 
-    @Override
     public void setVisible(boolean visible) {
         this.visible = visible;
     }
 
     @Override
-    public boolean getVisible() {
+    public boolean isVisible() {
         return visible;
     }
+
+    public int getControlTop() {
+        return y;
+    }
+
+    public void done() {
+    }
+
+    public abstract void filter(String lowerValue);
 }
index 4135bc9beab6dce8040a04a0cc1b48a71671972a..dba872b9402869a8b4489d0fbaee5f8f9b809ea4 100644 (file)
@@ -5,14 +5,15 @@ import net.minecraft.client.Minecraft;
 import java.util.ArrayList;
 import java.util.List;
 
-public class ControlListSection extends ControlListEntry {
+public class ControlListSection extends ControlListEntry implements IControlSet {
     private static final int TITLE_HEIGHT = 16;
-    private static final int CONTROLS_WIDTH = 310;
     private final String title;
-    private final List<IControl> controls = new ArrayList<>();
+    private final List<AbstractControl> controls = new ArrayList<>();
     private final Minecraft minecraft = Minecraft.getInstance();
     private final int titleHeight;
     private int height;
+    private IControl focused;
+    private boolean dragging;
 
     ControlListSection(String title, CreateControl... createControls) {
         this.title = title;
@@ -20,12 +21,12 @@ public class ControlListSection extends ControlListEntry {
         this.height = titleHeight;
 
         int columnCount = columnCount();
-        int controlWidth = (CONTROLS_WIDTH - ((columnCount - 1) * 4)) / columnCount;
+        int controlWidth = (ControlList.CONTROLS_WIDTH - ((columnCount - 1) * 4)) / columnCount;
 
         int column = 0;
         for (CreateControl createControl : createControls) {
-            IControl control = createControl.create(0, controlWidth);
-            if(control == null) continue;
+            AbstractControl control = createControl.create(controlWidth);
+            if (control == null) continue;
 
             this.controls.add(control);
             if (column == 0) {
@@ -36,10 +37,11 @@ public class ControlListSection extends ControlListEntry {
     }
 
     private int columnCount() {
-        switch (minecraft.getLanguageManager().getCurrentLanguage().getCode()){
+        switch (minecraft.getLanguageManager().getCurrentLanguage().getCode()) {
             case "en_au":
             case "en_us":
-            case "en_gb": return 3;
+            case "en_gb":
+                return 3;
         }
         return 2;
     }
@@ -49,24 +51,24 @@ public class ControlListSection extends ControlListEntry {
         int x = this.getX();
         int y = this.getY();
         int top = y;
-        if(this.title != null) {
+        if (this.title != null) {
             this.minecraft.fontRenderer.drawString(this.title, x + 4, y + ((TITLE_HEIGHT - this.minecraft.fontRenderer.FONT_HEIGHT) / 1.5f), 16777215);
             top += titleHeight;
         }
 
         int left = 0;
         int height = 0;
-        for(IControl control : controls) {
-            if(!control.getVisible()) continue;
+        for (AbstractControl control : controls) {
+            if (!control.isVisible()) continue;
 
             control.setX(left + x);
             control.setY(top);
             control.render(mouseX, mouseY);
-            if(left == 0) {
+            if (left == 0) {
                 height = control.getControlHeight();
             }
             left += control.getControlWidth();
-            if(left >= CONTROLS_WIDTH) {
+            if (left >= ControlList.CONTROLS_WIDTH) {
                 left = 0;
                 top += height;
             }
@@ -74,49 +76,36 @@ public class ControlListSection extends ControlListEntry {
     }
 
     @Override
-    public int getControlHeight() {
-        return this.height;
-    }
-
-    @Override
-    public int getControlWidth() {
-        return CONTROLS_WIDTH;
+    public void clearFocus() {
+        IControlSet.super.clearFocus();
     }
 
     @Override
-    public boolean mouseClicked(double mouseX, double mouseY, int button) {
-        for (IControl control : controls) {
-            if (control.getVisible() && control.mouseClicked(mouseX, mouseY, button)) {
-                return true;
-            }
-        }
-        return false;
+    public int getControlHeight() {
+        return this.height;
     }
 
-    @Override
-    public boolean mouseReleased(double mouseX, double mouseY, int button) {
-        boolean result = false;
-        for (IControl control : controls) {
-            if (control.mouseReleased(mouseX, mouseY, button)) result = true;
-        }
-        return result;
+    public int getControlWidth() {
+        return ControlList.CONTROLS_WIDTH;
     }
 
-    @Override
     public void filter(String lowerValue) {
-        if(matchesTitle(lowerValue)) lowerValue = "";
+        if (matchesTitle(lowerValue)) lowerValue = "";
 
         int height = 0;
         int left = 0;
-        for (IControl entry : controls) {
+        for (AbstractControl entry : controls) {
             entry.filter(lowerValue);
-            if (entry.getVisible()) {
+            if (entry.isVisible()) {
                 if (left == 0)
                     height += entry.getControlHeight();
                 left += entry.getControlWidth();
                 if (left >= getControlWidth()) {
                     left = 0;
                 }
+            } else if (entry == focused) {
+                entry.clearFocus();
+                focused = null;
             }
         }
         this.height = height + titleHeight;
@@ -130,4 +119,29 @@ public class ControlListSection extends ControlListEntry {
         return lowerString.startsWith(lowerValue) ||
                 lowerString.contains(" " + lowerValue);
     }
+
+    @Override
+    public List<? extends IControl> controls() {
+        return this.controls;
+    }
+
+    @Override
+    public IControl getFocused() {
+        return this.focused;
+    }
+
+    @Override
+    public void setFocused(IControl focused) {
+        this.focused = focused;
+    }
+
+    @Override
+    public boolean isDragging() {
+        return dragging;
+    }
+
+    @Override
+    public void setDragging(boolean dragging) {
+        this.dragging = dragging;
+    }
 }
index 7ea950fb530865316da41ef02a42da11a5076e66..b91c8db396d96d75725eef1aaa1d8594642ff078 100644 (file)
@@ -2,5 +2,5 @@ package com.irtimaled.bbor.client.gui;
 
 @FunctionalInterface
 interface CreateControl {
-    IControl create(Integer x, Integer width);
+    AbstractControl create(Integer width);
 }
index 17db2ba985d11affd4ae0dbd58ce796e9382baf6..871db3829d1709149454356ff48628dda787a1a0 100644 (file)
@@ -2,23 +2,8 @@ package com.irtimaled.bbor.client.gui;
 
 import net.minecraft.client.gui.IGuiEventListener;
 
-interface IControl extends IGuiEventListener {
+interface IControl extends IFocusableControl, IGuiEventListener {
     void render(int mouseX, int mouseY);
 
-    void setX(int x);
-
-    void setY(int y);
-
-    int getControlWidth();
-
-    int getControlHeight();
-
-    boolean getVisible();
-
-    void setVisible(boolean visible);
-
-    void filter(String lowerValue);
-
-    default void close() {
-    }
+    boolean isVisible();
 }
diff --git a/src/main/java/com/irtimaled/bbor/client/gui/IControlSet.java b/src/main/java/com/irtimaled/bbor/client/gui/IControlSet.java
new file mode 100644 (file)
index 0000000..86a9b37
--- /dev/null
@@ -0,0 +1,94 @@
+package com.irtimaled.bbor.client.gui;
+
+import net.minecraft.client.gui.IGuiEventListener;
+
+import java.util.List;
+
+public interface IControlSet extends IFocusableControl, IGuiEventListener {
+    List<? extends IControl> controls();
+
+    IControl getFocused();
+
+    void setFocused(IControl control);
+
+    boolean isDragging();
+
+    void setDragging(boolean dragging);
+
+    default boolean mouseClicked(double mouseX, double mouseY, int button) {
+        for (IControl control : this.controls()) {
+            if (control.isVisible() && control.mouseClicked(mouseX, mouseY, button)) {
+                IControl focused = getFocused();
+                if (focused != null && focused != control) {
+                    focused.clearFocus();
+                }
+                this.setFocused(control);
+                if (button == 0) this.setDragging(true);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    default boolean mouseReleased(double mouseX, double mouseY, int button) {
+        this.setDragging(false);
+        IControl focused = this.getFocused();
+        return focused != null && focused.mouseReleased(mouseX, mouseY, button);
+    }
+
+    default boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
+        IControl focused = this.getFocused();
+        return focused != null && this.isDragging() && button == 0 && focused.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
+    }
+
+    default boolean mouseScrolled(double mouseX, double mouseY, double scrollAmount) {
+        IControl focused = this.getFocused();
+        return focused != null && focused.mouseScrolled(mouseX, mouseY, scrollAmount);
+    }
+
+    default boolean keyPressed(int key, int scanCode, int modifiers) {
+        IControl focused = this.getFocused();
+        return focused != null && focused.keyPressed(key, scanCode, modifiers);
+    }
+
+    default boolean keyReleased(int key, int scanCode, int modifiers) {
+        IControl focused = this.getFocused();
+        return focused != null && focused.keyReleased(key, scanCode, modifiers);
+    }
+
+    default boolean charTyped(char character, int modifiers) {
+        IControl focused = this.getFocused();
+        return focused != null && focused.charTyped(character, modifiers);
+    }
+
+    default boolean changeFocus(boolean moveForward) {
+        IControl focused = this.getFocused();
+        if (focused != null && focused.changeFocus(moveForward)) {
+            return true;
+        }
+
+        List<? extends IControl> controls = this.controls();
+        int controlIndex = controls.indexOf(focused);
+        int newIndex;
+        if (focused != null && controlIndex >= 0) {
+            newIndex = controlIndex + (moveForward ? 1 : 0);
+        } else if (moveForward) {
+            newIndex = 0;
+        } else {
+            newIndex = controls.size();
+        }
+
+        if (ListHelper.findNextMatch(controls, newIndex, moveForward,
+                c -> c.changeFocus(moveForward), this::setFocused)) return true;
+        this.setFocused(null);
+        return false;
+    }
+
+    default void clearFocus() {
+        IControl focused = getFocused();
+        if (focused != null) {
+            setFocused(null);
+            focused.clearFocus();
+        }
+    }
+}
diff --git a/src/main/java/com/irtimaled/bbor/client/gui/IFocusableControl.java b/src/main/java/com/irtimaled/bbor/client/gui/IFocusableControl.java
new file mode 100644 (file)
index 0000000..ab58bc9
--- /dev/null
@@ -0,0 +1,6 @@
+package com.irtimaled.bbor.client.gui;
+
+public interface IFocusableControl {
+    default void clearFocus() {
+    }
+}
index 34fadec2468c77f68fa8f41bfa59269f3c6c3ca9..e94cdeb522b0afca15c67121f1a7ff3f908ee6d2 100644 (file)
@@ -12,18 +12,20 @@ class IntSettingSlider extends AbstractSlider {
 
     final Setting<Integer> setting;
     final int minValue;
-    final int range;
 
     IntSettingSlider(int width, int minValue, int maxValue, String format, Setting<Integer> setting) {
-        super(0, 0, width);
+        super(width, maxValue - minValue);
         this.setting = setting;
         this.minValue = minValue;
         this.format = format;
-        this.range = maxValue - minValue;
-        this.setProgress(getSliderValue());
+        setInitialPosition();
         this.updateText();
     }
 
+    protected void setInitialPosition() {
+        this.setPosition(this.setting.get() - this.minValue);
+    }
+
     IntSettingSlider addDisplayValue(int value, String displayValue) {
         displayValues.put(value, displayValue);
         if (setting.get() == value) {
@@ -32,26 +34,18 @@ class IntSettingSlider extends AbstractSlider {
         return this;
     }
 
-    private String getDisplayValue() {
-        Integer value = setting.get();
-        return I18n.format(format, displayValues.getOrDefault(value, value.toString()));
-    }
-
     protected Integer getSettingValue() {
-        return minValue + (int) (range * progress);
+        return minValue + getPosition();
     }
 
-    protected double getSliderValue() {
-        return (setting.get() - minValue) / (double) range;
-    }
-
-    @Override
-    protected void updateText() {
-        this.setMessage(this.getDisplayValue());
+    private void updateText() {
+        Integer value = setting.get();
+        this.setMessage(I18n.format(format, displayValues.getOrDefault(value, value.toString())));
     }
 
     @Override
     protected void onProgressChanged() {
         this.setting.set(this.getSettingValue());
+        updateText();
     }
 }
diff --git a/src/main/java/com/irtimaled/bbor/client/gui/ListHelper.java b/src/main/java/com/irtimaled/bbor/client/gui/ListHelper.java
new file mode 100644 (file)
index 0000000..c9f0a3f
--- /dev/null
@@ -0,0 +1,24 @@
+package com.irtimaled.bbor.client.gui;
+
+import java.util.List;
+import java.util.ListIterator;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+public class ListHelper {
+    public static <T> boolean findNextMatch(List<? extends T> list, int index, boolean forward, Predicate<T> match, Consumer<T> consumer) {
+        ListIterator<? extends T> iterator = list.listIterator(index);
+        Supplier<Boolean> hasMore = forward ? iterator::hasNext : iterator::hasPrevious;
+        Supplier<T> more = forward ? iterator::next : iterator::previous;
+
+        while (hasMore.get()) {
+            T item = more.get();
+            if (match.test(item)) {
+                consumer.accept(item);
+                return true;
+            }
+        }
+        return false;
+    }
+}
index 6b5dcf0222a978d2579a1e5fbd5802027590e727..c8add06855ed3d3604e7d61363b7fdec311d9425 100644 (file)
@@ -1,6 +1,7 @@
 package com.irtimaled.bbor.client.gui;
 
 import com.irtimaled.bbor.client.interop.ClientInterop;
+import net.minecraft.client.gui.IGuiEventListener;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.resources.I18n;
 import net.minecraft.util.text.StringTextComponent;
@@ -27,7 +28,7 @@ public abstract class ListScreen extends Screen {
 
     @Override
     protected void init() {
-        this.controlList = new ControlList(this.width, this.height, 48, this.height - 28);
+        this.controlList = this.buildList(48, this.height - 28);
         this.searchField = new SearchField(this.font, this.width / 2 - 100, 22, 200, 20, this.controlList);
         this.doneButton = new AbstractButton(this.width / 2 - 100, this.height - 24, 200, I18n.format("gui.done")) {
             @Override
@@ -36,13 +37,12 @@ public abstract class ListScreen extends Screen {
             }
         };
 
-        this.children.add(this.doneButton);
-        this.children.add(this.controlList);
         this.children.add(this.searchField);
-        this.setup();
+        this.children.add(this.controlList);
+        this.children.add(this.doneButton);
     }
 
-    protected abstract void setup();
+    protected abstract ControlList buildList(int top, int bottom);
 
     @Override
     public void render(int mouseX, int mouseY, float unknown) {
@@ -82,11 +82,23 @@ public abstract class ListScreen extends Screen {
         this.controlList.close();
     }
 
-    ControlList getControlList() {
-        return this.controlList;
+    protected void setCanExit(boolean canExit) {
+        this.doneButton.active = canExit;
     }
 
-    AbstractButton getDoneButton() {
-        return doneButton;
+    @Override
+    public boolean mouseClicked(double mouseX, double mouseY, int button) {
+        for (IGuiEventListener control : this.children()) {
+            if (control.mouseClicked(mouseX, mouseY, button)) {
+                IGuiEventListener focused = getFocused();
+                if (focused instanceof IFocusableControl && focused != control) {
+                    ((IFocusableControl) focused).clearFocus();
+                }
+                this.setFocused(control);
+                if (button == 0) this.setDragging(true);
+                return true;
+            }
+        }
+        return false;
     }
 }
index d26c6793046fdcb64368e03d7db6076d8f7683a3..90a4a01eb5b2e48ed3a6479ced6a2c432540da30 100644 (file)
@@ -8,33 +8,39 @@ import net.minecraft.world.storage.WorldSummary;
 import java.util.List;
 
 public class LoadSavesScreen extends ListScreen {
+    private SelectableControlList controlList;
+
     public static void show() {
         ClientInterop.displayScreen(new LoadSavesScreen());
     }
 
     @Override
-    protected void setup() {
-        ControlList controlList = this.getControlList();
-        controlList.showSelectionBox();
+    protected ControlList buildList(int top, int bottom) {
+        controlList = new SelectableControlList(this.width, this.height, top, bottom);
         try {
             final SaveFormat saveLoader = this.minecraft.getSaveLoader();
             List<WorldSummary> saveList = saveLoader.getSaveList();
             saveList.sort(null);
-            saveList.forEach(world -> controlList.add(new WorldSaveRow(world, saveLoader)));
+            saveList.forEach(world -> controlList.add(new WorldSaveRow(world, saveLoader, controlList::setSelectedEntry)));
         } catch (AnvilConverterException e) {
             e.printStackTrace();
         }
+        return controlList;
     }
 
     @Override
     protected void onDoneClicked() {
-        ((WorldSaveRow) this.getControlList().getSelectedEntry()).loadWorld();
+        getSelectedEntry().done();
     }
 
     @Override
     public void render(int mouseX, int mouseY, float unknown) {
-        ControlListEntry selectedEntry = this.getControlList().getSelectedEntry();
-        this.getDoneButton().active = selectedEntry != null && selectedEntry.getVisible();
+        ControlListEntry selectedEntry = getSelectedEntry();
+        this.setCanExit(selectedEntry != null && selectedEntry.isVisible());
         super.render(mouseX, mouseY, unknown);
     }
+
+    private ControlListEntry getSelectedEntry() {
+        return this.controlList.getSelectedEntry();
+    }
 }
index 7c6562e449a4164e301de235b83228f59e156f5a..4e3651a122982ca9db6a6b6092478bbe223856ba 100644 (file)
@@ -9,7 +9,7 @@ class MaxYSettingSlider extends IntSettingSlider {
     MaxYSettingSlider(int width, int minValue, Setting<Integer> setting) {
         super(width, minValue - 2, 127, I18n.format("bbor.options.maxY", "%s"), setting);
         this.actualMinValue = minValue;
-        this.setProgress(getSliderValue());
+        this.setInitialPosition();
         this.addDisplayValue(-1, I18n.format("bbor.options.maxY.activated"));
         this.addDisplayValue(0, I18n.format("bbor.options.maxY.player"));
         this.addDisplayValue(63, I18n.format("bbor.options.maxY.seaLevel"));
@@ -24,11 +24,13 @@ class MaxYSettingSlider extends IntSettingSlider {
     }
 
     @Override
-    protected double getSliderValue() {
+    protected void setInitialPosition() {
+        if (actualMinValue != minValue + 2) return;
+
         int value = setting.get();
         if (value < actualMinValue)
             value = (value - 1) + actualMinValue;
 
-        return (value - minValue) / (double) range;
+        setPosition(value - minValue);
     }
 }
index 4778f4d163c71a50adab7d7a34f38a65c4c93ea3..d5fd4e23fb797c36a9c56fe4c17c3562c84ea23e 100644 (file)
@@ -3,7 +3,7 @@ package com.irtimaled.bbor.client.gui;
 import net.minecraft.client.gui.FontRenderer;
 import net.minecraft.client.gui.widget.TextFieldWidget;
 
-public class SearchField extends TextFieldWidget {
+public class SearchField extends TextFieldWidget implements IControl {
     private final ControlList controlList;
 
     SearchField(FontRenderer fontRenderer, int left, int top, int width, int height, ControlList controlList) {
@@ -13,19 +13,19 @@ public class SearchField extends TextFieldWidget {
         this.func_212954_a(text -> this.controlList.filter(removeLeadingSpaces(text.toLowerCase())));
         this.setTextFormatter((text, id) -> removeLeadingSpaces(text));
         this.setFocused(true);
-        this.setCanLoseFocus(false);
     }
 
     private String removeLeadingSpaces(String text) {
         return text.replaceFirst("^\\s++", "");
     }
 
+    @Override
     public void render(int mouseX, int mouseY) {
         this.render(mouseX, mouseY, 0f);
     }
 
     @Override
-    public void setFocused(boolean ignored) {
-        super.setFocused(true);
+    public boolean isVisible() {
+        return super.getVisible();
     }
 }
diff --git a/src/main/java/com/irtimaled/bbor/client/gui/SelectableControlList.java b/src/main/java/com/irtimaled/bbor/client/gui/SelectableControlList.java
new file mode 100644 (file)
index 0000000..0584a23
--- /dev/null
@@ -0,0 +1,109 @@
+package com.irtimaled.bbor.client.gui;
+
+import com.irtimaled.bbor.client.renderers.Renderer;
+import org.lwjgl.opengl.GL11;
+
+public class SelectableControlList extends ControlList {
+    private final int listRight;
+
+    private int selectedElement;
+    private boolean isFocused;
+
+    SelectableControlList(int width, int height, int top, int bottom) {
+        super(width, height, top, bottom);
+        this.listRight = this.listLeft + CONTROLS_WIDTH;
+        this.selectedElement = -1;
+    }
+
+    @Override
+    public void filter(String lowerValue) {
+        super.filter(lowerValue);
+        if (selectedElement >= 0) {
+            if (selectNextVisibleElement(true, selectedElement) ||
+                    selectNextVisibleElement(true, 0)) return;
+            selectedElement = -1;
+        }
+    }
+
+    @Override
+    public boolean keyPressed(int key, int scanCode, int modifiers) {
+        if (key != 264 && key != 265 && key != 257) return false;
+
+        if (key == 257) {
+            if (selectedElement >= 0) {
+                getSelectedEntry().done();
+                return true;
+            }
+            return false;
+        }
+
+        boolean moveForward = key == 264;
+        if (selectedElement >= 0) {
+            int newIndex = selectedElement + (moveForward ? 1 : 0);
+            if (selectNextVisibleElement(moveForward, newIndex)) return true;
+        }
+        if (selectNextVisibleElement(moveForward, moveForward ? 0 : entries.size())) return true;
+
+        this.selectedElement = -1;
+        return false;
+    }
+
+    private boolean selectNextVisibleElement(boolean moveForward, int index) {
+        return ListHelper.findNextMatch(entries, index, moveForward, ControlListEntry::isVisible,
+                entry -> this.selectedElement = entry.index);
+    }
+
+    ControlListEntry getSelectedEntry() {
+        return this.selectedElement >= 0 && this.selectedElement < this.entries.size() ?
+                this.entries.get(this.selectedElement) :
+                null;
+    }
+
+    void setSelectedEntry(ControlListEntry entry) {
+        if (entry != null) {
+            this.selectedElement = entry.index;
+        } else {
+            this.selectedElement = -1;
+        }
+    }
+
+    @Override
+    public boolean changeFocus(boolean moveForward) {
+        if (contentHeight == PADDING) return false;
+
+        isFocused = !isFocused;
+        if (getSelectedEntry() == null && this.entries.size() > 0) {
+            setSelectedEntry(this.entries.get(0));
+        }
+        return isFocused;
+    }
+
+    @Override
+    protected void drawEntry(int mouseX, int mouseY, int top, ControlListEntry entry, int height) {
+        if (this.selectedElement == entry.index) {
+            GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
+            GL11.glDisable(GL11.GL_TEXTURE_2D);
+            int color = this.isFocused ? 255 : 128;
+            Renderer.startTextured()
+                    .setAlpha(255)
+                    .setColor(color, color, color)
+                    .addPoint((double) this.listLeft - 2, (double) (top + height) - 2, 0.0D, 0.0D, 1.0D)
+                    .addPoint((double) this.listRight + 2, (double) (top + height) - 2, 0.0D, 1.0D, 1.0D)
+                    .addPoint((double) this.listRight + 2, top - 2, 0.0D, 1.0D, 0.0D)
+                    .addPoint((double) this.listLeft - 2, top - 2, 0.0D, 0.0D, 0.0D)
+                    .setColor(0, 0, 0)
+                    .addPoint(this.listLeft - 1, (double) (top + height) - 3, 0.0D, 0.0D, 1.0D)
+                    .addPoint(this.listRight + 1, (double) (top + height) - 3, 0.0D, 1.0D, 1.0D)
+                    .addPoint(this.listRight + 1, top - 1, 0.0D, 1.0D, 0.0D)
+                    .addPoint(this.listLeft - 1, top - 1, 0.0D, 0.0D, 0.0D)
+                    .render();
+            GL11.glEnable(GL11.GL_TEXTURE_2D);
+        }
+        super.drawEntry(mouseX, mouseY, top, entry, height);
+    }
+
+    @Override
+    public void clearFocus() {
+        this.isFocused = false;
+    }
+}
index d8db2656091782868dc2e91e55b3e3903ddfaef4..cce48a2754b5af323a243d9e6a17c082ff424029 100644 (file)
@@ -28,14 +28,14 @@ public class SettingsScreen extends ListScreen {
     }
 
     @Override
-    protected void setup() {
+    protected ControlList buildList(int top, int bottom) {
         String version = SharedConstants.getVersion().getName();
-        ControlList controlList = this.getControlList();
+        ControlList controlList = new ControlList(this.width, this.height, top, bottom);
         if (this.minecraft.world != null) controlList.setTransparentBackground();
 
         controlList
                 .section(null,
-                        (x, width) -> new BoolButton(width, I18n.format("bbor.options.active"), this.minecraft.world != null) {
+                        width -> new BoolButton(width, I18n.format("bbor.options.active"), this.minecraft.world != null) {
                             @Override
                             public void onPressed() {
                                 ClientRenderer.toggleActive();
@@ -46,61 +46,62 @@ public class SettingsScreen extends ListScreen {
                                 return ClientRenderer.getActive();
                             }
                         },
-                        (x, width) -> new BoolSettingButton(width, I18n.format("bbor.options.outerBoxOnly"), ConfigManager.outerBoxesOnly),
-                        (x, width) -> new BoolSettingButton(width, I18n.format("bbor.options.fill"), ConfigManager.fill))
+                        width -> new BoolSettingButton(width, I18n.format("bbor.options.outerBoxOnly"), ConfigManager.outerBoxesOnly),
+                        width -> new BoolSettingButton(width, I18n.format("bbor.options.fill"), ConfigManager.fill))
                 .section(I18n.format("bbor.features.spawnChunks"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawnChunks"), BoundingBoxType.WorldSpawn),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.lazyChunks"), BoundingBoxType.LazySpawnChunks),
-                        (x, width) -> new MaxYSettingSlider(width, 39, ConfigManager.worldSpawnMaxY))
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawnChunks"), BoundingBoxType.WorldSpawn),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.lazyChunks"), BoundingBoxType.LazySpawnChunks),
+                        width -> new MaxYSettingSlider(width, 39, ConfigManager.worldSpawnMaxY))
                 .section(I18n.format("bbor.features.slimeChunks"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.slimeChunks"), BoundingBoxType.SlimeChunks),
-                        (x, width) -> new MaxYSettingSlider(width, 39, ConfigManager.slimeChunkMaxY))
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.slimeChunks"), BoundingBoxType.SlimeChunks),
+                        width -> new MaxYSettingSlider(width, 39, ConfigManager.slimeChunkMaxY))
                 .section(I18n.format("bbor.features.biomeBorders"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.biomeBorders"), BoundingBoxType.BiomeBorder),
-                        (x, width) -> new MaxYSettingSlider(width, 1, ConfigManager.biomeBordersMaxY),
-                        (x, width) -> new IntSettingSlider(width, 1, 3, "bbor.options.distance", ConfigManager.biomeBordersRenderDistance)
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.biomeBorders"), BoundingBoxType.BiomeBorder),
+                        width -> new MaxYSettingSlider(width, 1, ConfigManager.biomeBordersMaxY),
+                        width -> new IntSettingSlider(width, 1, 3, "bbor.options.distance", ConfigManager.biomeBordersRenderDistance)
                                 .addDisplayValue(1, I18n.format("bbor.options.distance.nearest"))
                                 .addDisplayValue(2, I18n.format("bbor.options.distance.nearer"))
                                 .addDisplayValue(3, I18n.format("bbor.options.distance.normal")))
                 .section(I18n.format("bbor.features.mobSpawners"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.mobSpawners"), BoundingBoxType.MobSpawner),
-                        (x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.mobSpawners.spawnArea"), ConfigManager.renderMobSpawnerSpawnArea),
-                        (x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.mobSpawners.activationLines"), ConfigManager.renderMobSpawnerActivationLines))
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.mobSpawners"), BoundingBoxType.MobSpawner),
+                        width -> new BoolSettingButton(width, I18n.format("bbor.features.mobSpawners.spawnArea"), ConfigManager.renderMobSpawnerSpawnArea),
+                        width -> new BoolSettingButton(width, I18n.format("bbor.features.mobSpawners.activationLines"), ConfigManager.renderMobSpawnerActivationLines))
                 .section(I18n.format("bbor.sections.beaconsAndConduits"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.beacons"), BoundingBoxType.Beacon),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.conduits"), BoundingBoxType.Conduit),
-                        (x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.conduits.mobHarmArea"), ConfigManager.renderConduitMobHarmArea))
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.beacons"), BoundingBoxType.Beacon),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.conduits"), BoundingBoxType.Conduit),
+                        width -> new BoolSettingButton(width, I18n.format("bbor.features.conduits.mobHarmArea"), ConfigManager.renderConduitMobHarmArea))
                 .section(I18n.format("bbor.features.spawnableBlocks"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawnableBlocks"), BoundingBoxType.SpawnableBlocks),
-                        (x, width) -> new IntSettingSlider(width, 1, 3, "bbor.options.distance.y", ConfigManager.spawnableBlocksRenderHeight)
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawnableBlocks"), BoundingBoxType.SpawnableBlocks),
+                        width -> new IntSettingSlider(width, 1, 3, "bbor.options.distance.y", ConfigManager.spawnableBlocksRenderHeight)
                                 .addDisplayValue(1, "2")
                                 .addDisplayValue(2, "4")
                                 .addDisplayValue(3, "8"),
-                        (x, width) -> new IntSettingSlider(width, 1, 3, "bbor.options.distance.xz", ConfigManager.spawnableBlocksRenderWidth)
+                        width -> new IntSettingSlider(width, 1, 3, "bbor.options.distance.xz", ConfigManager.spawnableBlocksRenderWidth)
                                 .addDisplayValue(1, "8")
                                 .addDisplayValue(2, "16")
                                 .addDisplayValue(3, "32"))
                 .section(I18n.format("bbor.features.spawningSpheres"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawningSpheres"), BoundingBoxType.AFKSphere),
-                        (x, width) -> new BoolSettingButton(width, I18n.format("bbor.features.spawnableBlocks"), ConfigManager.renderAFKSpawnableBlocks))
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.features.spawningSpheres"), BoundingBoxType.AFKSphere),
+                        width -> new BoolSettingButton(width, I18n.format("bbor.features.spawnableBlocks"), ConfigManager.renderAFKSpawnableBlocks))
                 .section(I18n.format("bbor.tabs.structures"),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.desertTemples"), BoundingBoxType.DesertTemple),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.jungleTemples"), BoundingBoxType.JungleTemple),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.witchHuts"), BoundingBoxType.WitchHut),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.mansions"), BoundingBoxType.Mansion),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.monuments"), BoundingBoxType.OceanMonument),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.igloos"), BoundingBoxType.Igloo),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.oceanRuins"), BoundingBoxType.OceanRuin),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.buriedTreasure"), BoundingBoxType.BuriedTreasure),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.shipwrecks"), BoundingBoxType.Shipwreck),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.strongholds"), BoundingBoxType.Stronghold),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.mineshafts"), BoundingBoxType.MineShaft),
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.villages"), BoundingBoxType.Village),
-                        (x, width) -> version.matches(pillagerOutpostVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.pillagerOutposts"), BoundingBoxType.PillagerOutpost) : null,
-                        (x, width) -> version.matches(bastionRemnantVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.ruinedPortal"), BoundingBoxType.RuinedPortal) : null,
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.fortresses"), BoundingBoxType.NetherFortress),
-                        (x, width) -> version.matches(netherFossilVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.netherFossils"), BoundingBoxType.NetherFossil) : null,
-                        (x, width) -> version.matches(bastionRemnantVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.bastionRemnants"), BoundingBoxType.BastionRemnant) : null,
-                        (x, width) -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.endCities"), BoundingBoxType.EndCity));
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.desertTemples"), BoundingBoxType.DesertTemple),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.jungleTemples"), BoundingBoxType.JungleTemple),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.witchHuts"), BoundingBoxType.WitchHut),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.mansions"), BoundingBoxType.Mansion),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.monuments"), BoundingBoxType.OceanMonument),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.igloos"), BoundingBoxType.Igloo),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.oceanRuins"), BoundingBoxType.OceanRuin),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.buriedTreasure"), BoundingBoxType.BuriedTreasure),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.shipwrecks"), BoundingBoxType.Shipwreck),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.strongholds"), BoundingBoxType.Stronghold),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.mineshafts"), BoundingBoxType.MineShaft),
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.villages"), BoundingBoxType.Village),
+                        width -> version.matches(pillagerOutpostVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.pillagerOutposts"), BoundingBoxType.PillagerOutpost) : null,
+                        width -> version.matches(bastionRemnantVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.ruinedPortal"), BoundingBoxType.RuinedPortal) : null,
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.fortresses"), BoundingBoxType.NetherFortress),
+                        width -> version.matches(netherFossilVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.netherFossils"), BoundingBoxType.NetherFossil) : null,
+                        width -> version.matches(bastionRemnantVersionPattern) ? new BoundingBoxTypeButton(width, I18n.format("bbor.structures.bastionRemnants"), BoundingBoxType.BastionRemnant) : null,
+                        width -> new BoundingBoxTypeButton(width, I18n.format("bbor.structures.endCities"), BoundingBoxType.EndCity));
+        return controlList;
     }
 }
index 5dde418443244ec29f0d0deccbb9a0a2cb1969b9..f0268e454def8a68851853e31d00aa1f4e6cf5bf 100644 (file)
@@ -21,6 +21,7 @@ import java.io.InputStream;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.function.Consumer;
 
 public class WorldSaveRow extends ControlListEntry implements Comparable<WorldSaveRow> {
     private static final Logger LOGGER = LogManager.getLogger();
@@ -30,15 +31,17 @@ public class WorldSaveRow extends ControlListEntry implements Comparable<WorldSa
     private final Minecraft client;
     private final WorldSummary worldSummary;
     private final SaveFormat saveLoader;
+    private final Consumer<ControlListEntry> setSelectedEntry;
     private final ResourceLocation iconLocation;
     private final DynamicTexture icon;
 
     private File iconFile;
     private long lastClickTime;
 
-    WorldSaveRow(WorldSummary worldSummary, SaveFormat saveLoader) {
+    WorldSaveRow(WorldSummary worldSummary, SaveFormat saveLoader, Consumer<ControlListEntry> setSelectedEntry) {
         this.worldSummary = worldSummary;
         this.saveLoader = saveLoader;
+        this.setSelectedEntry = setSelectedEntry;
         this.client = Minecraft.getInstance();
         this.iconLocation = new ResourceLocation("worlds/" + Hashing.sha1().hashUnencodedChars(worldSummary.getFileName()) + "/icon");
         this.iconFile = saveLoader.getFile(worldSummary.getFileName(), "icon.png");
@@ -49,24 +52,29 @@ public class WorldSaveRow extends ControlListEntry implements Comparable<WorldSa
         this.icon = this.loadIcon();
     }
 
+    @Override
+    public boolean isMouseOver(double mouseX, double mouseY) {
+        return mouseX > this.getX() &&
+                mouseX < this.getX() + ControlList.CONTROLS_WIDTH &&
+                mouseY > this.getY() &&
+                mouseY < this.getY() + this.getControlHeight();
+    }
+
     @Override
     public boolean mouseClicked(double mouseX, double mouseY, int button) {
-        this.list.setSelectedIndex(this.index);
+        if (!isMouseOver(mouseX, mouseY)) return false;
+
+        this.setSelectedEntry.accept(this);
         if (Util.milliTime() - this.lastClickTime < 250L) {
-            loadWorld();
-            return true;
+            done();
         } else {
             this.lastClickTime = Util.milliTime();
-            return false;
         }
+        return true;
     }
 
     @Override
-    public boolean mouseReleased(double mouseX, double mouseY, int button) {
-        return false;
-    }
-
-    void loadWorld() {
+    public void done() {
         String fileName = this.worldSummary.getFileName();
         WorldInfo worldInfo = saveLoader.getWorldInfo(fileName);
         long seed = worldInfo.getSeed();
@@ -105,14 +113,9 @@ public class WorldSaveRow extends ControlListEntry implements Comparable<WorldSa
         GL11.glDisable(GL11.GL_BLEND);
     }
 
-    @Override
-    public int getControlWidth() {
-        return 310;
-    }
-
     @Override
     public void filter(String lowerValue) {
-        setVisible(lowerValue == "" ||
+        super.setVisible(lowerValue.isEmpty() ||
                 this.worldSummary.getDisplayName().toLowerCase().contains(lowerValue) ||
                 this.worldSummary.getFileName().toLowerCase().contains(lowerValue));
     }
index 121b5540c57903ce148b579484c542c59f3a80d2..5ba8d5657bd5c680d75eb8b6e500304395a0e4af 100644 (file)
@@ -25,6 +25,8 @@ public class MixinGuiOptions extends Screen {
             if (button.y >= top && button.y < bottom)
                 button.y -= 12;
         }
-        this.addButton(new SettingsScreenButton(this.width / 2 - 155, top + 84, 150, "BBOR", this));
+        SettingsScreenButton button = new SettingsScreenButton(this.width / 2 - 155, top + 84, 150, "BBOR", this);
+        this.buttons.add(this.buttons.size() - 1, button);
+        this.children.add(this.children.size() - 1, button);
     }
 }