public interface GuiRenderer {

    ReadablePoint getOpenGlOffset();

    MatrixStack getMatrixStack();

    ReadableDimension getSize();

    void setDrawingArea(int x, int y, int width, int height);

    void bindTexture(Identifier location);

    void bindTexture(int glId);

    void drawTexturedRect(int x, int y, int u, int v, int width, int height);

    void drawTexturedRect(int x, int y, int u, int v, int width, int height, int uWidth, int vHeight, int textureWidth, int textureHeight);

    void drawRect(int x, int y, int width, int height, int color);

    void drawRect(int x, int y, int width, int height, ReadableColor color);

    void drawRect(int x, int y, int width, int height, int topLeftColor, int topRightColor, int bottomLeftColor, int bottomRightColor);

    void drawRect(int x, int y, int width, int height, ReadableColor topLeftColor, ReadableColor topRightColor, ReadableColor bottomLeftColor, ReadableColor bottomRightColor);

    int drawString(int x, int y, int color, String text);

    int drawString(int x, int y, ReadableColor color, String text);

    int drawCenteredString(int x, int y, int color, String text);

    int drawCenteredString(int x, int y, ReadableColor color, String text);

    int drawString(int x, int y, int color, String text, boolean shadow);

    int drawString(int x, int y, ReadableColor color, String text, boolean shadow);

    int drawCenteredString(int x, int y, int color, String text, boolean shadow);

    int drawCenteredString(int x, int y, ReadableColor color, String text, boolean shadow);

    /**
     * Inverts all colors on the screen.
     * @param right Right border of the inverted rectangle
     * @param bottom Bottom border of the inverted rectangle
     * @param left Left border of the inverted rectangle
     * @param top Top border of the inverted rectangle
     */
    void invertColors(int right, int bottom, int left, int top);

} public class RenderInfo {
    public final float partialTick;
    public final int mouseX;
    public final int mouseY;
    public final int layer;

    public RenderInfo(float partialTick, int mouseX, int mouseY, int layer) {
        this.partialTick = partialTick;
        this.mouseX = mouseX;
        this.mouseY = mouseY;
        this.layer = layer;
    }

    public RenderInfo offsetMouse(int minusX, int minusY) {
        return new RenderInfo(partialTick, mouseX - minusX, mouseY - minusY, layer);
    }

    public RenderInfo layer(int layer) {
        return this.layer == layer ? this : new RenderInfo(partialTick, mouseX, mouseY, layer);
    }

    public void addTo(CrashReport crashReport) {
        CrashReportSection category = crashReport.addElement("Render info details");
        MCVer.addDetail(category, "Partial Tick", () -> "" + partialTick);
        MCVer.addDetail(category, "Mouse X", () -> "" + mouseX);
        MCVer.addDetail(category, "Mouse Y", () -> "" + mouseY);
        MCVer.addDetail(category, "Layer", () -> "" + layer);
    }

    public float getPartialTick() {
        return this.partialTick;
    }

    public int getMouseX() {
        return this.mouseX;
    }

    public int getMouseY() {
        return this.mouseY;
    }

    public int getLayer() {
        return this.layer;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RenderInfo that = (RenderInfo) o;
        return Float.compare(that.partialTick, partialTick) == 0 &&
                mouseX == that.mouseX &&
                mouseY == that.mouseY &&
                layer == that.layer;
    }

    @Override
    public int hashCode() {
        return Objects.hash(partialTick, mouseX, mouseY, layer);
    }

    @Override
    public String toString() {
        return "RenderInfo{" +
                "partialTick=" + partialTick +
                ", mouseX=" + mouseX +
                ", mouseY=" + mouseY +
                ", layer=" + layer +
                '}';
    }
} public interface GuiContainer<T extends GuiContainer<T>> extends ComposedGuiElement<T> {

    T setLayout(Layout layout);
    Layout getLayout();

    void convertFor(GuiElement element, Point point);

    /**
     * Converts the global coordinates of the point to ones relative to the element.
     * @param element The element, must be part of this container
     * @param point The point
     * @param relativeLayer Layer at which the point is relative to this element,
     *                      positive values are above this element
     */
    void convertFor(GuiElement element, Point point, int relativeLayer);

    Map<GuiElement, LayoutData> getElements();
    T addElements(LayoutData layoutData, GuiElement... elements);
    T removeElement(GuiElement element);
    T sortElements();
    T sortElements(Comparator<GuiElement> comparator);

    ReadableColor getBackgroundColor();
    T setBackgroundColor(ReadableColor backgroundColor);
} public class GuiPanel extends AbstractGuiContainer<GuiPanel> {

    public GuiPanel() {
    }

    public GuiPanel(GuiContainer container) {
        super(container);
    }

    GuiPanel(Layout layout, int width , int height, Map<GuiElement, LayoutData> withElements) {
        setLayout(layout);
        if (width != 0 || height != 0) {
            setSize(width, height);
        }
        for (Map.Entry<GuiElement, LayoutData> e : withElements.entrySet()) {
            addElements(e.getValue(), e.getKey());
        }
    }

    public static GuiPanelBuilder builder() {
        return new GuiPanelBuilder();
    }

    @Override
    protected GuiPanel getThis() {
        return this;
    }

    public static class GuiPanelBuilder {
        private Layout layout;
        private int width;
        private int height;
        private ArrayList<GuiElement> withElements$key;
        private ArrayList<LayoutData> withElements$value;

        GuiPanelBuilder() {
        }

        public GuiPanelBuilder layout(Layout layout) {
            this.layout = layout;
            return this;
        }

        public GuiPanelBuilder width(int width) {
            this.width = width;
            return this;
        }

        public GuiPanelBuilder height(int height) {
            this.height = height;
            return this;
        }

        public GuiPanelBuilder with(GuiElement withKey, LayoutData withValue) {
            if (this.withElements$key == null) {
                this.withElements$key = new ArrayList<GuiElement>();
                this.withElements$value = new ArrayList<LayoutData>();
            }
            this.withElements$key.add(withKey);
            this.withElements$value.add(withValue);
            return this;
        }

        public GuiPanelBuilder withElements(Map<? extends GuiElement, ? extends LayoutData> withElements) {
            if (this.withElements$key == null) {
                this.withElements$key = new ArrayList<GuiElement>();
                this.withElements$value = new ArrayList<LayoutData>();
            }
            for (final Map.Entry<? extends GuiElement, ? extends LayoutData> $lombokEntry : withElements.entrySet()) {
                this.withElements$key.add($lombokEntry.getKey());
                this.withElements$value.add($lombokEntry.getValue());
            }
            return this;
        }

        public GuiPanelBuilder clearWithElements() {
            if (this.withElements$key != null) {
                this.withElements$key.clear();
                this.withElements$value.clear();
            }
            return this;
        }

        public GuiPanel build() {
            Map<GuiElement, LayoutData> withElements;
            switch (this.withElements$key == null ? 0 : this.withElements$key.size()) {
                case 0:
                    withElements = java.util.Collections.emptyMap();
                    break;
                case 1:
                    withElements = java.util.Collections.singletonMap(this.withElements$key.get(0), this.withElements$value.get(0));
                    break;
                default:
                    withElements = new java.util.LinkedHashMap<GuiElement, LayoutData>(this.withElements$key.size() < 1073741824 ? 1 + this.withElements$key.size() + (this.withElements$key.size() - 3) / 3 : Integer.MAX_VALUE);
                    for (int $i = 0; $i < this.withElements$key.size(); $i++)
                        withElements.put(this.withElements$key.get($i), (LayoutData) this.withElements$value.get($i));
                    withElements = java.util.Collections.unmodifiableMap(withElements);
            }

            return new GuiPanel(layout, width, height, withElements);
        }

        public String toString() {
            return "GuiPanel.GuiPanelBuilder(layout=" + this.layout + ", width=" + this.width + ", height=" + this.height + ", withElements$key=" + this.withElements$key + ", withElements$value=" + this.withElements$value + ")";
        }
    }
} public class GuiScrollable extends AbstractGuiScrollable<GuiScrollable> {
    public GuiScrollable() {
    }

    public GuiScrollable(GuiContainer container) {
        super(container);
    }

    @Override
    protected GuiScrollable getThis() {
        return this;
    }
} public class GuiVerticalList extends AbstractGuiVerticalList<GuiVerticalList> {
    public GuiVerticalList() {
    }

    public GuiVerticalList(GuiContainer container) {
        super(container);
    }

    @Override
    protected GuiVerticalList getThis() {
        return this;
    }
} public class GuiButton extends AbstractGuiButton<GuiButton> {
    public GuiButton() {
    }

    public GuiButton(GuiContainer container) {
        super(container);
    }

    @Override
    protected GuiButton getThis() {
        return this;
    }
} public interface GuiElement<T extends GuiElement<T>> {

    MinecraftClient getMinecraft();

    GuiContainer getContainer();
    T setContainer(GuiContainer container);

    void layout(ReadableDimension size, RenderInfo renderInfo);
    void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo);

    ReadableDimension getMinSize();
    ReadableDimension getMaxSize();

    T setMaxSize(ReadableDimension maxSize);

    boolean isEnabled();
    T setEnabled(boolean enabled);
    T setEnabled();
    T setDisabled();

    GuiElement getTooltip(RenderInfo renderInfo);
    T setTooltip(GuiElement tooltip);

    /**
     * Returns the layer this element takes part in.
     * The standard layer is layer 0. Event handlers will be called for this layer.
     * @return The layer of this element
     */
    int getLayer();

} public class GuiTextField extends AbstractGuiTextField<GuiTextField> {
    public GuiTextField() {
    }

    public GuiTextField(GuiContainer container) {
        super(container);
    }

    @Override
    protected GuiTextField getThis() {
        return this;
    }
} public class GuiDropdownMenu<V> extends AbstractGuiDropdownMenu<V, GuiDropdownMenu<V>> {

    public GuiDropdownMenu() {
    }

    public GuiDropdownMenu(GuiContainer container) {
        super(container);
    }

    @Override
    protected GuiDropdownMenu<V> getThis() {
        return this;
    }
} public interface Typeable {
    boolean typeKey(ReadablePoint mousePosition, int keyCode, char keyChar, boolean ctrlDown, boolean shiftDown);
} public abstract class CustomLayout<T extends GuiContainer<T>> implements Layout {
    private final Layout parent;
    private final Map<GuiElement, Pair<Point, Dimension>> result = new LinkedHashMap<>();

    public CustomLayout() {
        this(null);
    }

    public CustomLayout(Layout parent) {
        this.parent = parent;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> layOut(GuiContainer container, ReadableDimension size) {
        result.clear();
        if (parent == null) {
            Collection<GuiElement> elements = container.getChildren();
            for (GuiElement element : elements) {
                result.put(element, Pair.of(new Point(0, 0), new Dimension(element.getMinSize())));
            }
        } else {
            Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> elements = parent.layOut(container, size);
            for (Map.Entry<GuiElement, Pair<ReadablePoint, ReadableDimension>> entry : elements.entrySet()) {
                Pair<ReadablePoint, ReadableDimension> pair = entry.getValue();
                result.put(entry.getKey(), Pair.of(new Point(pair.getLeft()), new Dimension(pair.getRight())));
            }
        }

        layout((T) container, size.getWidth(), size.getHeight());

        return (Map) result;
    }

    private Pair<Point, Dimension> entry(GuiElement element) {
        return result.get(element);
    }

    protected void set(GuiElement element, int x, int y, int width, int height) {
        Pair<Point, Dimension> entry = entry(element);
        entry.getLeft().setLocation(x, y);
        entry.getRight().setSize(width, height);
    }

    protected void pos(GuiElement element, int x, int y) {
        entry(element).getLeft().setLocation(x, y);
    }

    protected void size(GuiElement element, ReadableDimension size) {
        size.getSize(entry(element).getRight());
    }

    protected void size(GuiElement element, int width, int height) {
        entry(element).getRight().setSize(width, height);
    }

    protected void x(GuiElement element, int x) {
        entry(element).getLeft().setX(x);
    }

    protected void y(GuiElement element, int y) {
        entry(element).getLeft().setY(y);
    }

    protected void width(GuiElement element, int width) {
        entry(element).getRight().setWidth(width);
    }

    protected void height(GuiElement element, int height) {
        entry(element).getRight().setHeight(height);
    }

    protected int x(GuiElement element) {
        return entry(element).getLeft().getX();
    }

    protected int y(GuiElement element) {
        return entry(element).getLeft().getY();
    }

    protected int width(GuiElement element) {
        return entry(element).getRight().getWidth();
    }

    protected int height(GuiElement element) {
        return entry(element).getRight().getHeight();
    }

    protected abstract void layout(T container, int width, int height);

    @Override
    public ReadableDimension calcMinSize(GuiContainer<?> container) {
        return new Dimension(0, 0);
    }
} public class HorizontalLayout implements Layout {
    private static final Data DEFAULT_DATA = new Data(0);

    private final Alignment alignment;

    private int spacing;

    public HorizontalLayout() {
        this(Alignment.LEFT);
    }

    public HorizontalLayout(Alignment alignment) {
        this.alignment = alignment;
    }

    @Override
    public Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> layOut(GuiContainer<?> container, ReadableDimension size) {
        int x = 0;
        int spacing = 0;
        Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> map = new LinkedHashMap<>();
        for (Map.Entry<GuiElement, LayoutData> entry : container.getElements().entrySet()) {
            x += spacing;
            spacing = this.spacing;

            GuiElement element  = entry.getKey();
            Data data = entry.getValue() instanceof Data ? (Data) entry.getValue() : DEFAULT_DATA;
            Dimension elementSize = new Dimension(element.getMinSize());
            ReadableDimension elementMaxSize = element.getMaxSize();
            elementSize.setWidth(Math.min(size.getWidth() - x, Math.min(elementSize.getWidth(), elementMaxSize.getWidth())));
            elementSize.setHeight(Math.min(size.getHeight(), elementMaxSize.getHeight()));
            int remainingHeight = size.getHeight() - elementSize.getHeight();
            int y = (int) (data.alignment * remainingHeight);
            map.put(element, Pair.<ReadablePoint, ReadableDimension>of(new Point(x, y), elementSize));
            x += elementSize.getWidth();
        }
        if (alignment != Alignment.LEFT) {
            int remaining = size.getWidth() - x;
            if (alignment == Alignment.CENTER) {
                remaining /= 2;
            }
            for (Pair<ReadablePoint, ReadableDimension> pair : map.values()) {
                ((Point) pair.getLeft()).translate(remaining, 0);
            }
        }
        return map;
    }

    @Override
    public ReadableDimension calcMinSize(GuiContainer<?> container) {
        int maxHeight = 0;
        int width = 0;
        int spacing = 0;
        for (Map.Entry<GuiElement, LayoutData> entry : container.getElements().entrySet()) {
            width += spacing;
            spacing = this.spacing;

            GuiElement element = entry.getKey();
            ReadableDimension minSize = element.getMinSize();
            int height = minSize.getHeight();
            if (height > maxHeight) {
                maxHeight = height;
            }
            width += minSize.getWidth();
        }
        return new Dimension(width, maxHeight);
    }

    public int getSpacing() {
        return this.spacing;
    }

    public HorizontalLayout setSpacing(int spacing) {
        this.spacing = spacing;
        return this;
    }

    public static class Data implements LayoutData {
        private double alignment;

        public Data() {
            this(0);
        }

        public Data(double alignment) {
            this.alignment = alignment;
        }

        public double getAlignment() {
            return this.alignment;
        }

        public void setAlignment(double alignment) {
            this.alignment = alignment;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Data data = (Data) o;
            return Double.compare(data.alignment, alignment) == 0;
        }

        @Override
        public int hashCode() {
            return Objects.hash(alignment);
        }

        @Override
        public String toString() {
            return "Data{" +
                    "alignment=" + alignment +
                    '}';
        }
    }

    public enum Alignment {
        LEFT, RIGHT, CENTER
    }
} public class VerticalLayout implements Layout {
    private static final Data DEFAULT_DATA = new Data(0);

    private final Alignment alignment;

    private int spacing;

    public VerticalLayout() {
        this(Alignment.TOP);
    }

    public VerticalLayout(Alignment alignment) {
        this.alignment = alignment;
    }

    @Override
    public Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> layOut(GuiContainer<?> container, ReadableDimension size) {
        int y = 0;
        int spacing = 0;
        Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> map = new LinkedHashMap<>();
        for (Map.Entry<GuiElement, LayoutData> entry : container.getElements().entrySet()) {
            y += spacing;
            spacing = this.spacing;

            GuiElement element  = entry.getKey();
            Data data = entry.getValue() instanceof Data ? (Data) entry.getValue() : DEFAULT_DATA;
            Dimension elementSize = new Dimension(element.getMinSize());
            ReadableDimension elementMaxSize = element.getMaxSize();
            elementSize.setHeight(Math.min(size.getHeight() - y, Math.min(elementSize.getHeight(), elementMaxSize.getHeight())));
            elementSize.setWidth(Math.min(size.getWidth(), (data.maximizeWidth ? elementMaxSize : elementSize).getWidth()));
            int remainingWidth = size.getWidth() - elementSize.getWidth();
            int x = (int) (data.alignment * remainingWidth);
            map.put(element, Pair.<ReadablePoint, ReadableDimension>of(new Point(x, y), elementSize));
            y += elementSize.getHeight();
        }
        if (alignment != Alignment.TOP) {
            int remaining = size.getHeight() - y;
            if (alignment == Alignment.CENTER) {
                remaining /= 2;
            }
            for (Pair<ReadablePoint, ReadableDimension> pair : map.values()) {
                ((Point) pair.getLeft()).translate(0, remaining);
            }
        }
        return map;
    }

    @Override
    public ReadableDimension calcMinSize(GuiContainer<?> container) {
        int maxWidth = 0;
        int height = 0;
        int spacing = 0;
        for (Map.Entry<GuiElement, LayoutData> entry : container.getElements().entrySet()) {
            height += spacing;
            spacing = this.spacing;

            GuiElement element = entry.getKey();
            ReadableDimension minSize = element.getMinSize();
            int width = minSize.getWidth();
            if (width > maxWidth) {
                maxWidth = width;
            }
            height += minSize.getHeight();
        }
        return new Dimension(maxWidth, height);
    }

    public int getSpacing() {
        return this.spacing;
    }

    public VerticalLayout setSpacing(int spacing) {
        this.spacing = spacing;
        return this;
    }

    public static class Data implements LayoutData {
        private double alignment;
        private boolean maximizeWidth;

        public Data() {
            this(0);
        }

        public Data(double alignment) {
            this(alignment, true);
        }

        public Data(double alignment, boolean maximizeWidth) {
            this.alignment = alignment;
            this.maximizeWidth = maximizeWidth;
        }

        public double getAlignment() {
            return this.alignment;
        }

        public boolean isMaximizeWidth() {
            return this.maximizeWidth;
        }

        public void setAlignment(double alignment) {
            this.alignment = alignment;
        }

        public void setMaximizeWidth(boolean maximizeWidth) {
            this.maximizeWidth = maximizeWidth;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Data data = (Data) o;
            return Double.compare(data.alignment, alignment) == 0 &&
                    maximizeWidth == data.maximizeWidth;
        }

        @Override
        public int hashCode() {
            return Objects.hash(alignment, maximizeWidth);
        }

        @Override
        public String toString() {
            return "Data{" +
                    "alignment=" + alignment +
                    ", maximizeWidth=" + maximizeWidth +
                    '}';
        }
    }

    public enum Alignment {
        TOP, BOTTOM, CENTER
    }
} public interface Colors extends ReadableColor {
    ReadableColor TRANSPARENT = new Color(0, 0, 0, 0);
    ReadableColor LIGHT_TRANSPARENT = new Color(0, 0, 0, 64);
    ReadableColor HALF_TRANSPARENT = new Color(0, 0, 0, 128);
    ReadableColor DARK_TRANSPARENT = new Color(0, 0, 0, 192);
    ReadableColor LIGHT_GRAY = new Color(192, 192, 192);
    ReadableColor DARK_RED = new Color(170, 0, 0);
} public interface Consumer<T> {
    void consume(T obj);
} public class MCVer {
    public static MinecraftClient getMinecraft() {
        return MinecraftClient.getInstance();
    }

    private static class ScissorBounds {
        private static final ScissorBounds DISABLED = new ScissorBounds(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
        private final int x;
        private final int y;
        private final int width;
        private final int height;

        private ScissorBounds(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ScissorBounds that = (ScissorBounds) o;
            return x == that.x && y == that.y && width == that.width && height == that.height;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y, width, height);
        }
    }
    private static final ArrayDeque<ScissorBounds> scissorStateStack = new ArrayDeque<>();
    private static ScissorBounds scissorState = ScissorBounds.DISABLED;

    public static void pushScissorState() {
        scissorStateStack.push(scissorState);
    }

    public static void popScissorState() {
        setScissorBounds(scissorStateStack.pop());
    }

    public static void setScissorBounds(int x, int y, int width, int height) {
        setScissorBounds(new ScissorBounds(x, y, width, height));
    }

    public static void setScissorDisabled() {
        setScissorBounds(ScissorBounds.DISABLED);
    }

    private static void setScissorBounds(ScissorBounds newState) {
        ScissorBounds oldState = MCVer.scissorState;
        if (Objects.equals(oldState, newState)) {
            return;
        }

        scissorState = newState;

        boolean isEnabled = newState != ScissorBounds.DISABLED;
        boolean wasEnabled = oldState != ScissorBounds.DISABLED;

        if (isEnabled) {
            if (!wasEnabled) {
                GL11.glEnable(GL11.GL_SCISSOR_TEST);
            }
            GL11.glScissor(scissorState.x, scissorState.y, scissorState.width, scissorState.height);
        } else {
            GL11.glDisable(GL11.GL_SCISSOR_TEST);
        }
    }

    //#if MC>=11400
    public static Window newScaledResolution(MinecraftClient mc) {
        //#if MC>=11500
        return mc.getWindow();
        //#else
        //$$ return mc.window;
        //#endif
    }
    //#else
    //$$ public static ScaledResolution newScaledResolution(Minecraft mc) {
        //#if MC>=10809
        //$$ return new ScaledResolution(mc);
        //#else
        //$$ return new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
        //#endif
    //$$ }
    //#endif

    public static void addDetail(CrashReportSection category, String name, Callable<String> callable) {
        //#if MC>=10904
        //#if MC>=11200
        category.add(name, callable::call);
        //#else
        //$$ category.setDetail(name, callable::call);
        //#endif
        //#else
        //$$ category.addCrashSectionCallable(name, callable);
        //#endif
    }

    public static void drawRect(int right, int bottom, int left, int top) {
        //#if MC>=10800
        Tessellator tessellator = Tessellator.getInstance();
        //#else
        //$$ Tessellator tessellator = Tessellator.instance;
        //#endif
        //#if MC>=10904
        BufferBuilder vertexBuffer = tessellator.getBuffer();
        //#else
        //#if MC>=10800
        //$$ WorldRenderer vertexBuffer = tessellator.getWorldRenderer();
        //#else
        //$$ Tessellator vertexBuffer = tessellator;
        //#endif
        //#endif
        //#if MC>=10809
        //#if MC>=11700
        //$$ vertexBuffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION);
        //#else
        vertexBuffer.begin(GL11.GL_QUADS, VertexFormats.POSITION);
        //#endif
        vertexBuffer.vertex(right, top, 0).next();
        vertexBuffer.vertex(left, top, 0).next();
        vertexBuffer.vertex(left, bottom, 0).next();
        vertexBuffer.vertex(right, bottom, 0).next();
        //#else
        //$$ vertexBuffer.startDrawingQuads();
        //$$ vertexBuffer.addVertex(right, top, 0);
        //$$ vertexBuffer.addVertex(left, top, 0);
        //$$ vertexBuffer.addVertex(left, bottom, 0);
        //$$ vertexBuffer.addVertex(right, bottom, 0);
        //#endif
        tessellator.draw();
    }

    public static void drawRect(int x, int y, int width, int height, ReadableColor tl, ReadableColor tr, ReadableColor bl, ReadableColor br) {
        //#if MC>=10800
        Tessellator tessellator = Tessellator.getInstance();
        BufferBuilder vertexBuffer = tessellator.getBuffer();
        //#else
        //$$ Tessellator tessellator = Tessellator.instance;
        //$$ Tessellator vertexBuffer = tessellator;
        //#endif
        //#if MC>=10809
        //#if MC>=11700
        //$$ vertexBuffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR);
        //#else
        vertexBuffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR);
        //#endif
        vertexBuffer.vertex(x, y + height, 0).color(bl.getRed(), bl.getGreen(), bl.getBlue(), bl.getAlpha()).next();
        vertexBuffer.vertex(x + width, y + height, 0).color(br.getRed(), br.getGreen(), br.getBlue(), br.getAlpha()).next();
        vertexBuffer.vertex(x + width, y, 0).color(tr.getRed(), tr.getGreen(), tr.getBlue(), tr.getAlpha()).next();
        vertexBuffer.vertex(x, y, 0).color(tl.getRed(), tl.getGreen(), tl.getBlue(), tl.getAlpha()).next();
        //#else
        //$$ vertexBuffer.startDrawingQuads();
        //$$ vertexBuffer.setColorRGBA(bl.getRed(), bl.getGreen(), bl.getBlue(), bl.getAlpha());
        //$$ vertexBuffer.addVertex(x, y + height, 0);
        //$$ vertexBuffer.setColorRGBA(br.getRed(), br.getGreen(), br.getBlue(), br.getAlpha());
        //$$ vertexBuffer.addVertex(x + width, y + height, 0);
        //$$ vertexBuffer.setColorRGBA(tr.getRed(), tr.getGreen(), tr.getBlue(), tr.getAlpha());
        //$$ vertexBuffer.addVertex(x + width, y, 0);
        //$$ vertexBuffer.setColorRGBA(tl.getRed(), tl.getGreen(), tl.getBlue(), tl.getAlpha());
        //$$ vertexBuffer.addVertex(x, y, 0);
        //#endif
        tessellator.draw();
    }

    public static TextRenderer getFontRenderer() {
        return getMinecraft().textRenderer;
    }

    //#if FABRIC<=0
    //$$ public static RenderGameOverlayEvent.ElementType getType(RenderGameOverlayEvent event) {
        //#if MC>=10904
        //$$ return event.getType();
        //#else
        //$$ return event.type;
        //#endif
    //$$ }
    //$$
    //$$ public static int getMouseX(GuiScreenEvent.DrawScreenEvent.Post event) {
        //#if MC>=10904
        //$$ return event.getMouseX();
        //#else
        //$$ return event.mouseX;
        //#endif
    //$$ }
    //$$
    //$$ public static int getMouseY(GuiScreenEvent.DrawScreenEvent.Post event) {
        //#if MC>=10904
        //$$ return event.getMouseY();
        //#else
        //$$ return event.mouseY;
        //#endif
    //$$ }
    //#endif

    public static void setClipboardString(String text) {
        //#if MC>=11400
        getMinecraft().keyboard.setClipboard(text);
        //#else
        //$$ GuiScreen.setClipboardString(text);
        //#endif
    }

    public static String getClipboardString() {
        //#if MC>=11400
        return getMinecraft().keyboard.getClipboard();
        //#else
        //$$ return GuiScreen.getClipboardString();
        //#endif
    }

    //#if MC<=10710
    //$$ public static void color(float r, float g, float b) { GL11.glColor3f(r, g, b); }
    //$$ public static void color(float r, float g, float b, float a) { GL11.glColor4f(r, g, b, a); }
    //$$ public static void enableBlend() { GL11.glEnable(GL_BLEND); }
    //$$ public static void enableTexture2D() { GL11.glEnable(GL_TEXTURE_2D); }
    //$$ public static void enableAlpha() { GL11.glEnable(GL_ALPHA_TEST); }
    //$$ public static void disableTexture2D() { GL11.glDisable(GL_TEXTURE_2D); }
    //$$ public static void disableAlpha() { GL11.glDisable(GL_ALPHA_TEST); }
    //$$ public static void blendFunc(int s, int d) { GL11.glBlendFunc(s, d); }
    //$$ public static void tryBlendFuncSeparate(int l, int r, int vl, int vr) { OpenGlHelper.glBlendFunc(l, r, vl, vr); }
    //$$ public static void shadeModel(int mode) { GL11.glShadeModel(mode); }
    //$$ public static void enableColorLogic() { GL11.glEnable(GL_COLOR_LOGIC_OP); }
    //$$ public static void disableColorLogic() { GL11.glDisable(GL_COLOR_LOGIC_OP); }
    //$$ public static void colorLogicOp(int op) { GL11.glLogicOp(op); }
    //#endif

    //#if MC>=11400
    public static abstract class Keyboard {
        public static final int KEY_ESCAPE = GLFW.GLFW_KEY_ESCAPE;
        public static final int KEY_HOME = GLFW.GLFW_KEY_HOME;
        public static final int KEY_END = GLFW.GLFW_KEY_END;
        public static final int KEY_UP = GLFW.GLFW_KEY_UP;
        public static final int KEY_DOWN = GLFW.GLFW_KEY_DOWN;
        public static final int KEY_LEFT = GLFW.GLFW_KEY_LEFT;
        public static final int KEY_RIGHT = GLFW.GLFW_KEY_RIGHT;
        public static final int KEY_BACK = GLFW.GLFW_KEY_BACKSPACE;
        public static final int KEY_DELETE = GLFW.GLFW_KEY_DELETE;
        public static final int KEY_RETURN = GLFW.GLFW_KEY_ENTER;
        public static final int KEY_TAB = GLFW.GLFW_KEY_TAB;
        public static final int KEY_A = GLFW.GLFW_KEY_A;
        public static final int KEY_C = GLFW.GLFW_KEY_C;
        public static final int KEY_V = GLFW.GLFW_KEY_V;
        public static final int KEY_X = GLFW.GLFW_KEY_X;

        public static void enableRepeatEvents(boolean enabled) {
            getMinecraft().keyboard.setRepeatEvents(enabled);
        }
    }
    //#endif
} public static abstract class Keyboard {
    public static final int KEY_ESCAPE = GLFW.GLFW_KEY_ESCAPE;
    public static final int KEY_HOME = GLFW.GLFW_KEY_HOME;
    public static final int KEY_END = GLFW.GLFW_KEY_END;
    public static final int KEY_UP = GLFW.GLFW_KEY_UP;
    public static final int KEY_DOWN = GLFW.GLFW_KEY_DOWN;
    public static final int KEY_LEFT = GLFW.GLFW_KEY_LEFT;
    public static final int KEY_RIGHT = GLFW.GLFW_KEY_RIGHT;
    public static final int KEY_BACK = GLFW.GLFW_KEY_BACKSPACE;
    public static final int KEY_DELETE = GLFW.GLFW_KEY_DELETE;
    public static final int KEY_RETURN = GLFW.GLFW_KEY_ENTER;
    public static final int KEY_TAB = GLFW.GLFW_KEY_TAB;
    public static final int KEY_A = GLFW.GLFW_KEY_A;
    public static final int KEY_C = GLFW.GLFW_KEY_C;
    public static final int KEY_V = GLFW.GLFW_KEY_V;
    public static final int KEY_X = GLFW.GLFW_KEY_X;

    public static void enableRepeatEvents(boolean enabled) {
        getMinecraft().keyboard.setRepeatEvents(enabled);
    }
}
import de.johni0702.minecraft.gui.GuiRenderer;
import de.johni0702.minecraft.gui.RenderInfo;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.container.GuiPanel;
import de.johni0702.minecraft.gui.container.GuiScrollable;
import de.johni0702.minecraft.gui.container.GuiVerticalList;
import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.element.GuiElement;
import de.johni0702.minecraft.gui.element.GuiTextField;
import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu;
import de.johni0702.minecraft.gui.function.Typeable;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.Consumer;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
import de.johni0702.minecraft.gui.versions.MCVer;
import java.io.File;
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import de.johni0702.minecraft.gui.versions.MCVer.Keyboard;
/*
 * This file is part of jGui API, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2016 johni0702 <https://github.com/johni0702>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package de.johni0702.minecraft.gui.popup;



//#if MC>=11400
//#else
//$$ import org.lwjgl.input.Keyboard;
//#endif

public class GuiFileChooserPopup extends AbstractGuiPopup<GuiFileChooserPopup> implements Typeable {
    public static GuiFileChooserPopup openSaveGui(GuiContainer container, String buttonLabel, String...fileExtensions) {
        GuiFileChooserPopup popup = new GuiFileChooserPopup(container, fileExtensions, false).setBackgroundColor(Colors.DARK_TRANSPARENT);
        popup.acceptButton.setI18nLabel(buttonLabel);
        popup.open();
        return popup;
    }

    public static GuiFileChooserPopup openLoadGui(GuiContainer container, String buttonLabel, String...fileExtensions) {
        GuiFileChooserPopup popup = new GuiFileChooserPopup(container, fileExtensions, true).setBackgroundColor(Colors.DARK_TRANSPARENT);
        popup.acceptButton.setI18nLabel(buttonLabel).setDisabled();
        popup.open();
        return popup;
    }

    private Consumer<File> onAccept = (file) -> {};
    private Runnable onCancel = () -> {};

    private final GuiScrollable pathScrollable = new GuiScrollable(popup) {
        @Override
        public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {