A TimeSlider is a (thin) box that executes (that is calls .begin() and .end() on) other boxes that it passes over when dragged horizontally around. This has been built for "subclassability". Change the drawing by changing this::defaultdrawsLines, change the population of elements that can be exe
| 25 | /** |
| 26 | * A TimeSlider is a (thin) box that executes (that is calls .begin() and .end() on) other boxes that it passes over when dragged horizontally |
| 27 | * around. |
| 28 | * <p> |
| 29 | * This has been built for "subclassability". Change the drawing by changing this::defaultdrawsLines, change the population of elements that can be |
| 30 | * executed by changing this::population, change the behavior by changing this::off, this::on, this::skipForward, this::skipBackward. |
| 31 | */ |
| 32 | public class TimeSlider extends Box { |
| 33 | |
| 34 | static public final Dict.Prop<TimeSlider> time = new Dict.Prop<>("time").toCanon().doc("the default red-line time slider. Set `_.time.frame.x` = something to move it around."); |
| 35 | static public final Dict.Prop<Double> velocity = new Dict.Prop<>("velocity").toCanon().doc("the rate at which this time slider is moving (that is, delta-frame.x per update)."); |
| 36 | static public final Dict.Prop<Boolean> isRunning = new Dict.Prop<>("isRunning").toCanon().doc("set this to true if you are smoothly changing time in a way that it makes sense to interpolate" + |
| 37 | " and dead-reckon off of. Automatically set to false when the frame is dragged around."); |
| 38 | |
| 39 | |
| 40 | public static Dict.Prop<BiFunctionOfBoxAnd<Double, Double>> localTime = new Dict.Prop<>("localTime") |
| 41 | .toCanon().type().doc("setting this property modifies"); |
| 42 | |
| 43 | Rect was = null; |
| 44 | |
| 45 | int width = 20; |
| 46 | private Map<Box, Double> currentMapping = new LinkedHashMap<>(); |
| 47 | private float currentMappingAtTime = 0; |
| 48 | |
| 49 | public float topLimit = Float.NEGATIVE_INFINITY; |
| 50 | public float bottomLimit = Float.POSITIVE_INFINITY; |
| 51 | |
| 52 | public boolean disable = false; |
| 53 | |
| 54 | public TimeSlider() { |
| 55 | this.properties.putToMap(Boxes.insideRunLoop, "main.__force_onscreen__", this::forceOnscreen); |
| 56 | this.properties.putToMap(Boxes.insideRunLoop, "main.__swipe__", this::swiper); |
| 57 | |
| 58 | this.properties.putToMap(Callbacks.onFrameChanged, "__dontInterpolate__", (box, next) -> { |
| 59 | this.properties.put(isRunning, false); |
| 60 | return next; |
| 61 | }); |
| 62 | |
| 63 | properties.put(frame, new Rect(0, 0, width, 5000)); |
| 64 | |
| 65 | this.properties.put(isRunning, false); |
| 66 | this.properties.put(Delete.undeletable, true); |
| 67 | this.properties.put(FrameManipulation.lockWidth, true); |
| 68 | this.properties.put(FrameManipulation.lockHeight, true); |
| 69 | this.properties.put(Boxes.dontSave, true); |
| 70 | this.properties.put(Box.name, "TimeSlider"); |
| 71 | |
| 72 | this.properties.computeIfAbsent(frameDrawing, this::defaultdrawsLines); |
| 73 | this.properties.put(velocity, 0d); |
| 74 | } |
| 75 | |
| 76 | protected boolean swiper() { |
| 77 | if (was == null) { |
| 78 | this.properties.put(velocity, 0d); |
| 79 | was = this.properties.get(frame).duplicate(); |
| 80 | } else { |
| 81 | Rect now = this.properties.get(frame); |
| 82 | if (now.x == was.x) { |
| 83 | this.properties.put(velocity, 0d); |
| 84 | } else { |