Эх сурвалжийг харах

Properly credit osu!framework

shedaniel 5 жил өмнө
parent
commit
d2b339bd31

+ 1 - 1
LICENSE

@@ -3,7 +3,7 @@ This is free and unencumbered software released into the public domain.
 Anyone is free to copy, modify, publish, use, compile, sell, or
 Anyone is free to copy, modify, publish, use, compile, sell, or
 distribute this software, either in source code form or as a compiled
 distribute this software, either in source code form or as a compiled
 binary, for any purpose, commercial or non-commercial, and by any
 binary, for any purpose, commercial or non-commercial, and by any
-means.
+means unless stated otherwise.
 
 
 In jurisdictions that recognize copyright laws, the author or authors
 In jurisdictions that recognize copyright laws, the author or authors
 of this software dedicate any and all copyright interest in the
 of this software dedicate any and all copyright interest in the

+ 13 - 18
src/main/java/me/shedaniel/clothconfig2/ClothConfigInitializer.java

@@ -6,7 +6,6 @@ import me.shedaniel.clothconfig2.gui.entries.DoubleListEntry;
 import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry;
 import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry;
 import me.shedaniel.clothconfig2.gui.entries.LongSliderEntry;
 import me.shedaniel.clothconfig2.gui.entries.LongSliderEntry;
 import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry;
 import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry;
-import me.shedaniel.clothconfig2.gui.widget.DynamicEntryListWidget;
 import me.shedaniel.clothconfig2.impl.EasingMethod;
 import me.shedaniel.clothconfig2.impl.EasingMethod;
 import me.shedaniel.clothconfig2.impl.EasingMethod.EasingMethodImpl;
 import me.shedaniel.clothconfig2.impl.EasingMethod.EasingMethodImpl;
 import me.shedaniel.clothconfig2.impl.EasingMethods;
 import me.shedaniel.clothconfig2.impl.EasingMethods;
@@ -29,10 +28,10 @@ import net.minecraft.item.Items;
 import net.minecraft.text.LiteralText;
 import net.minecraft.text.LiteralText;
 import net.minecraft.text.TranslatableText;
 import net.minecraft.text.TranslatableText;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.Identifier;
-import net.minecraft.util.math.MathHelper;
 import net.minecraft.util.registry.Registry;
 import net.minecraft.util.registry.Registry;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.ApiStatus;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileInputStream;
@@ -51,32 +50,28 @@ public class ClothConfigInitializer implements ClientModInitializer {
     private static double scrollStep = 19;
     private static double scrollStep = 19;
     private static double bounceBackMultiplier = .24;
     private static double bounceBackMultiplier = .24;
     
     
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     public static double handleScrollingPosition(double[] target, double scroll, double maxScroll, float delta, double start, double duration) {
     public static double handleScrollingPosition(double[] target, double scroll, double maxScroll, float delta, double start, double duration) {
-        if (getBounceBackMultiplier() >= 0) {
-            target[0] = clamp(target[0], maxScroll);
-            if (target[0] < 0) {
-                target[0] -= target[0] * (1 - getBounceBackMultiplier()) * delta / 3;
-            } else if (target[0] > maxScroll) {
-                target[0] = (target[0] - maxScroll) * (1 - (1 - getBounceBackMultiplier()) * delta / 3) + maxScroll;
-            }
-        } else
-            target[0] = clamp(target[0], maxScroll, 0);
-        if (!Precision.almostEquals(scroll, target[0], Precision.FLOAT_EPSILON))
-            return expoEase(scroll, target[0], Math.min((System.currentTimeMillis() - start) / duration * delta * 3, 1));
-        else
-            return target[0];
+        return ScrollingContainer.handleScrollingPosition(target, scroll, maxScroll, delta, start, duration);
     }
     }
     
     
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     public static double expoEase(double start, double end, double amount) {
     public static double expoEase(double start, double end, double amount) {
-        return start + (end - start) * getEasingMethod().apply(amount);
+        return ScrollingContainer.ease(start, end, amount, getEasingMethod());
     }
     }
     
     
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     public static double clamp(double v, double maxScroll) {
     public static double clamp(double v, double maxScroll) {
-        return clamp(v, maxScroll, DynamicEntryListWidget.SmoothScrollingSettings.CLAMP_EXTENSION);
+        return ScrollingContainer.clampExtension(v, maxScroll);
     }
     }
     
     
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval
     public static double clamp(double v, double maxScroll, double clampExtension) {
     public static double clamp(double v, double maxScroll, double clampExtension) {
-        return MathHelper.clamp(v, -clampExtension, maxScroll + clampExtension);
+        return ScrollingContainer.clampExtension(v, -clampExtension, maxScroll + clampExtension);
     }
     }
     
     
     public static EasingMethod getEasingMethod() {
     public static EasingMethod getEasingMethod() {

+ 234 - 0
src/main/java/me/shedaniel/clothconfig2/api/ScrollingContainer.java

@@ -0,0 +1,234 @@
+/*
+ * The smooth scrolling code is partially taken from osu-framework.
+ * <p>
+ * Copyright (c) 2020 ppy Pty Ltd <contact@ppy.sh>.
+ * Copyright (c) 2018, 2019, 2020 shedaniel.
+ * <p>
+ * 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:
+ * <p>
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * <p>
+ * 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 me.shedaniel.clothconfig2.api;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import me.shedaniel.clothconfig2.ClothConfigInitializer;
+import me.shedaniel.clothconfig2.gui.widget.DynamicEntryListWidget;
+import me.shedaniel.clothconfig2.impl.EasingMethod;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.math.impl.PointHelper;
+import net.minecraft.client.render.BufferBuilder;
+import net.minecraft.client.render.Tessellator;
+import net.minecraft.client.render.VertexFormats;
+import net.minecraft.util.math.MathHelper;
+import org.jetbrains.annotations.ApiStatus;
+
+@ApiStatus.Internal
+public abstract class ScrollingContainer {
+    public double scrollAmount;
+    public double scrollTarget;
+    public long start;
+    public long duration;
+    public boolean draggingScrollBar = false;
+    
+    public abstract Rectangle getBounds();
+    
+    public Rectangle getScissorBounds() {
+        Rectangle bounds = getBounds();
+        if (hasScrollBar()) {
+            return new Rectangle(bounds.x, bounds.y, bounds.width - 6, bounds.height);
+        }
+        return bounds;
+    }
+    
+    public int getScrollBarX() {
+        return hasScrollBar() ? getBounds().getMaxX() - 6 : getBounds().getMaxX();
+    }
+    
+    public boolean hasScrollBar() {
+        return getMaxScrollHeight() > getBounds().height;
+    }
+    
+    public abstract int getMaxScrollHeight();
+    
+    public final int getMaxScroll() {
+        return Math.max(0, getMaxScrollHeight() - getBounds().height);
+    }
+    
+    public final double clamp(double v) {
+        return this.clamp(v, 200.0D);
+    }
+    
+    public final double clamp(double v, double clampExtension) {
+        return MathHelper.clamp(v, -clampExtension, (double) this.getMaxScroll() + clampExtension);
+    }
+    
+    public final void offset(double value, boolean animated) {
+        scrollTo(scrollTarget + value, animated);
+    }
+    
+    public final void scrollTo(double value, boolean animated) {
+        scrollTo(value, animated, ClothConfigInitializer.getScrollDuration());
+    }
+    
+    public final void scrollTo(double value, boolean animated, long duration) {
+        scrollTarget = clamp(value);
+        
+        if (animated) {
+            start = System.currentTimeMillis();
+            this.duration = duration;
+        } else
+            scrollAmount = scrollTarget;
+    }
+    
+    public void updatePosition(float delta) {
+        double[] target = new double[]{this.scrollTarget};
+        this.scrollAmount = handleScrollingPosition(target, this.scrollAmount, this.getMaxScroll(), delta, this.start, this.duration);
+        this.scrollTarget = target[0];
+    }
+    
+    public static double handleScrollingPosition(double[] target, double scroll, double maxScroll, float delta, double start, double duration) {
+        return handleScrollingPosition(target, scroll, maxScroll, delta, start, duration, ClothConfigInitializer.getBounceBackMultiplier(), ClothConfigInitializer.getEasingMethod());
+    }
+    
+    public static double handleScrollingPosition(double[] target, double scroll, double maxScroll, float delta, double start, double duration, double bounceBackMultiplier, EasingMethod easingMethod) {
+        if (bounceBackMultiplier >= 0) {
+            target[0] = clampExtension(target[0], maxScroll);
+            if (target[0] < 0) {
+                target[0] -= target[0] * (1 - bounceBackMultiplier) * delta / 3;
+            } else if (target[0] > maxScroll) {
+                target[0] = (target[0] - maxScroll) * (1 - (1 - bounceBackMultiplier) * delta / 3) + maxScroll;
+            }
+        } else
+            target[0] = clampExtension(target[0], maxScroll, 0);
+        if (!ClothConfigInitializer.Precision.almostEquals(scroll, target[0], ClothConfigInitializer.Precision.FLOAT_EPSILON))
+            return ease(scroll, target[0], Math.min((System.currentTimeMillis() - start) / duration * delta * 3, 1), easingMethod);
+        else
+            return target[0];
+    }
+    
+    public static double ease(double start, double end, double amount, EasingMethod easingMethod) {
+        return start + (end - start) * easingMethod.apply(amount);
+    }
+    
+    public static double clampExtension(double value, double maxScroll) {
+        return clampExtension(value, maxScroll, DynamicEntryListWidget.SmoothScrollingSettings.CLAMP_EXTENSION);
+    }
+    
+    public static double clampExtension(double v, double maxScroll, double clampExtension) {
+        return MathHelper.clamp(v, -clampExtension, maxScroll + clampExtension);
+    }
+    
+    public void renderScrollBar() {
+        renderScrollBar(0, 1, 1);
+    }
+    
+    public void renderScrollBar(int background, float alpha, float scrollBarAlphaOffset) {
+        if (hasScrollBar()) {
+            Rectangle bounds = getBounds();
+            int maxScroll = getMaxScroll();
+            int height = bounds.height * bounds.height / getMaxScrollHeight();
+            height = MathHelper.clamp(height, 32, bounds.height);
+            height -= Math.min((scrollAmount < 0 ? (int) -scrollAmount : scrollAmount > maxScroll ? (int) scrollAmount - maxScroll : 0), height * .95);
+            height = Math.max(10, height);
+            int minY = Math.min(Math.max((int) scrollAmount * (bounds.height - height) / maxScroll + bounds.y, bounds.y), bounds.getMaxY() - height);
+            
+            int scrollbarPositionMinX = getScrollBarX();
+            int scrollbarPositionMaxX = scrollbarPositionMinX + 6;
+            boolean hovered = (new Rectangle(scrollbarPositionMinX, minY, scrollbarPositionMaxX - scrollbarPositionMinX, height)).contains(PointHelper.ofMouse());
+            float bottomC = (hovered ? .67f : .5f) * scrollBarAlphaOffset;
+            float topC = (hovered ? .87f : .67f) * scrollBarAlphaOffset;
+            
+            RenderSystem.disableTexture();
+            RenderSystem.enableBlend();
+            RenderSystem.disableAlphaTest();
+            RenderSystem.blendFuncSeparate(770, 771, 1, 0);
+            RenderSystem.shadeModel(7425);
+            Tessellator tessellator = Tessellator.getInstance();
+            BufferBuilder buffer = tessellator.getBuffer();
+            {
+                float a = (background >> 24 & 255) / 255.0F;
+                float r = (background >> 16 & 255) / 255.0F;
+                float g = (background >> 8 & 255) / 255.0F;
+                float b = (background & 255) / 255.0F;
+                buffer.begin(7, VertexFormats.POSITION_COLOR);
+                buffer.vertex(scrollbarPositionMinX, bounds.getMaxY(), 0.0D).color(r, g, b, a).next();
+                buffer.vertex(scrollbarPositionMaxX, bounds.getMaxY(), 0.0D).color(r, g, b, a).next();
+                buffer.vertex(scrollbarPositionMaxX, bounds.y, 0.0D).color(r, g, b, a).next();
+                buffer.vertex(scrollbarPositionMinX, bounds.y, 0.0D).color(r, g, b, a).next();
+            }
+            tessellator.draw();
+            buffer.begin(7, VertexFormats.POSITION_COLOR);
+            buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
+            buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
+            buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
+            buffer.vertex(scrollbarPositionMinX, minY, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
+            tessellator.draw();
+            buffer.begin(7, VertexFormats.POSITION_COLOR);
+            buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).color(topC, topC, topC, alpha).next();
+            buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).color(topC, topC, topC, alpha).next();
+            buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).color(topC, topC, topC, alpha).next();
+            buffer.vertex(scrollbarPositionMinX, minY, 0.0D).color(topC, topC, topC, alpha).next();
+            tessellator.draw();
+            RenderSystem.shadeModel(7424);
+            RenderSystem.disableBlend();
+            RenderSystem.enableAlphaTest();
+            RenderSystem.enableTexture();
+        }
+    }
+    
+    public boolean mouseDragged(double mouseX, double mouseY, int button, double dx, double dy) {
+        return mouseDragged(mouseX, mouseY, button, dx, dy, false, 0);
+    }
+    
+    public boolean mouseDragged(double mouseX, double mouseY, int button, double dx, double dy, boolean snapToRows, double rowSize) {
+        if (button == 0 && draggingScrollBar) {
+            float height = getMaxScrollHeight();
+            Rectangle bounds = getBounds();
+            int actualHeight = bounds.height;
+            if (mouseY >= bounds.y && mouseY <= bounds.getMaxY()) {
+                double maxScroll = Math.max(1, getMaxScroll());
+                double int_3 = MathHelper.clamp(((double) (actualHeight * actualHeight) / (double) height), 32, actualHeight - 8);
+                double double_6 = Math.max(1.0D, maxScroll / (actualHeight - int_3));
+                float to = MathHelper.clamp((float) (scrollAmount + dy * double_6), 0, getMaxScroll());
+                if (snapToRows) {
+                    double nearestRow = Math.round(to / rowSize) * rowSize;
+                    scrollTo(nearestRow, false);
+                } else
+                    scrollTo(to, false);
+            }
+            return true;
+        }
+        return false;
+    }
+    
+    public boolean updateDraggingState(double mouseX, double mouseY, int button) {
+        if (!hasScrollBar())
+            return false;
+        double height = getMaxScroll();
+        Rectangle bounds = getBounds();
+        int actualHeight = bounds.height;
+        if (height > actualHeight && mouseY >= bounds.y && mouseY <= bounds.getMaxY()) {
+            double scrollbarPositionMinX = getScrollBarX();
+            if (mouseX >= scrollbarPositionMinX - 1 & mouseX <= scrollbarPositionMinX + 8) {
+                this.draggingScrollBar = true;
+                return true;
+            }
+        }
+        this.draggingScrollBar = false;
+        return false;
+    }
+}

+ 3 - 2
src/main/java/me/shedaniel/clothconfig2/gui/entries/DropdownBoxEntry.java

@@ -5,6 +5,7 @@ import com.google.common.collect.Lists;
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.EnvType;
@@ -35,7 +36,7 @@ import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 
 
-import static me.shedaniel.clothconfig2.ClothConfigInitializer.handleScrollingPosition;
+import static me.shedaniel.clothconfig2.api.ScrollingContainer.handleScrollingPosition;
 
 
 @SuppressWarnings("deprecation")
 @SuppressWarnings("deprecation")
 @Environment(EnvType.CLIENT)
 @Environment(EnvType.CLIENT)
@@ -482,7 +483,7 @@ public class DropdownBoxEntry<T> extends TooltipListEntry<T> {
         }
         }
         
         
         public void scrollTo(double value, boolean animated, long duration) {
         public void scrollTo(double value, boolean animated, long duration) {
-            target = ClothConfigInitializer.clamp(value, getMaxScrollPosition());
+            target = ScrollingContainer.clampExtension(value, getMaxScrollPosition());
             
             
             if (animated) {
             if (animated) {
                 start = System.currentTimeMillis();
                 start = System.currentTimeMillis();

+ 29 - 5
src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java

@@ -1,3 +1,27 @@
+/*
+ * The smooth scrolling code is partially taken from osu-framework.
+ * <p>
+ * Copyright (c) 2020 ppy Pty Ltd <contact@ppy.sh>.
+ * Copyright (c) 2018, 2019, 2020 shedaniel.
+ * <p>
+ * 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:
+ * <p>
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * <p>
+ * 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 me.shedaniel.clothconfig2.gui.widget;
 package me.shedaniel.clothconfig2.gui.widget;
 
 
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
@@ -14,8 +38,8 @@ import net.minecraft.util.Identifier;
 import net.minecraft.util.math.MathHelper;
 import net.minecraft.util.math.MathHelper;
 import net.minecraft.util.math.Matrix4f;
 import net.minecraft.util.math.Matrix4f;
 
 
-import static me.shedaniel.clothconfig2.ClothConfigInitializer.clamp;
-import static me.shedaniel.clothconfig2.ClothConfigInitializer.handleScrollingPosition;
+import static me.shedaniel.clothconfig2.api.ScrollingContainer.clampExtension;
+import static me.shedaniel.clothconfig2.api.ScrollingContainer.handleScrollingPosition;
 
 
 @Environment(EnvType.CLIENT)
 @Environment(EnvType.CLIENT)
 public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends DynamicEntryListWidget.Entry<E>> extends DynamicEntryListWidget<E> {
 public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends DynamicEntryListWidget.Entry<E>> extends DynamicEntryListWidget<E> {
@@ -42,8 +66,8 @@ public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends Dynamic
         if (!smoothScrolling)
         if (!smoothScrolling)
             this.scroll = MathHelper.clamp(double_1, 0.0D, this.getMaxScroll());
             this.scroll = MathHelper.clamp(double_1, 0.0D, this.getMaxScroll());
         else {
         else {
-            scroll = clamp(double_1, getMaxScroll());
-            target = clamp(double_1, getMaxScroll());
+            scroll = clampExtension(double_1, getMaxScroll());
+            target = clampExtension(double_1, getMaxScroll());
         }
         }
     }
     }
     
     
@@ -95,7 +119,7 @@ public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends Dynamic
     }
     }
     
     
     public void scrollTo(double value, boolean animated, long duration) {
     public void scrollTo(double value, boolean animated, long duration) {
-        target = clamp(value, getMaxScroll());
+        target = clampExtension(value, getMaxScroll());
         
         
         if (animated) {
         if (animated) {
             start = System.currentTimeMillis();
             start = System.currentTimeMillis();