<commit_before>package SW9.utility.helpers;

import SW9.model_canvas.ModelCanvas;
import SW9.utility.UndoRedoStack;
import SW9.utility.mouse.MouseTracker;
import javafx.beans.binding.NumberBinding;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;

import java.util.function.Function;
import java.util.function.Supplier;

public class DragHelper {

    public static <T extends Node & MouseTrackable> void makeDraggable(final T subject) {
        makeDraggable(subject, mouseEvent -> true);
    }

    public static <T extends Node & MouseTrackable> void makeDraggable(final T subject, final Function<MouseEvent, Boolean> conditional) {
        makeDraggable(subject, conditional, null);
    }

    public static <T extends Node & MouseTrackable> void makeDraggable(final T subject, final Function<MouseEvent, Boolean> conditional, final Supplier<Bounds> boundsSupplier) {
        final MouseTracker mouseTracker = subject.getMouseTracker();

        // The offset from the mouse
        final double[] dragXOffset = {0d};
        final double[] dragYOffset = {0d};

        // The offset from the draggable parent, used to undo
        final double[] parentXOffset = {0d};
        final double[] parentYOffset = {0d};

        // Variables to redo the drag later on
        final NumberBinding[] newXBinding = {null};
        final NumberBinding[] newYBinding = {null};
        final double[] newXValue = {0d};
        final double[] newYValue = {0d};

        final boolean[] hasDragged = {false};

        final EventHandler<MouseEvent> onMouseDragged = event -> {
            // Stop propagation of this event
            event.consume();

            // Check if we are allowed to drag in the first place
            if (!conditional.apply(event) || ModelCanvas.edgeIsBeingDrawn()) return;

            // Get the bounds (must be inside the lambda, because bounds might have changed from since we last moved the subject)
            final Bounds[] bounds = {null};
            if(boundsSupplier != null) {
                bounds[0] = boundsSupplier.get();
            }

            hasDragged[0] = true;

            // The location of the mouse (added with the relative to the subject)
            double x = event.getX() + dragXOffset[0];
            double y = event.getY() + dragYOffset[0];

            // Make coordinates snap to the grip on the canvas
            x -= x % ModelCanvas.GRID_SIZE - (ModelCanvas.GRID_SIZE / 2);
            y -= y % ModelCanvas.GRID_SIZE - (ModelCanvas.GRID_SIZE / 2);

            // If the subject has its x property bound have a parent where we can get the xProperty as well
            if (subject.xProperty().isBound()) {
                final LocationAware parent = findAncestor(subject);
                // Bind the x property of the subject to the value of the mouse event relative to the x property of the parent
                newXBinding[0] = parent.xProperty().add(x - parent.xProperty().get());
                if(bounds[0] != null && !bounds[0].contains((Double) newXBinding[0].getValue(), bounds[0].getMinY())) {
                    if((double) newXBinding[0].getValue() > bounds[0].getMaxX()) {
                        newXBinding[0] = newXBinding[0].multiply(0).add(bounds[0].getMaxX());
                    } else {
                        newXBinding[0] = newXBinding[0].multiply(0).add(bounds[0].getMinX());
                    }
                }
                subject.xProperty().bind(newXBinding[0]);
            } else {
                // Update the x property value to the value of the mouse
                newXValue[0] = x;
                subject.xProperty().setValue(x);
            }
            // If the subject has its y property bound have a parent where we can get the yProperty as well
            if (subject.yProperty().isBound()) {
                final LocationAware parent = findAncestor(subject);
                // Bind the y property of the subject to the value of the mouse event relative to the y property of the parent
                newYBinding[0] = parent.yProperty().add(y - parent.yProperty().get());
                if(bounds[0] != null && !bounds[0].contains(bounds[0].getMinX(), (Double) newYBinding[0].getValue())) {
                    if((double) newYBinding[0].getValue() > bounds[0].getMaxY()) {
                        newYBinding[0] = newYBinding[0].multiply(0).add(bounds[0].getMaxY());
                    } else {
                        newYBinding[0] = newYBinding[0].multiply(0).add(bounds[0].getMinY());
                    }
                }
                subject.yProperty().bind(newYBinding[0]);
            } else {
                // Update the y property value to the value of the mouse
                newYValue[0] = y;
                subject.yProperty().setValue(y);
            }

            subject.setCursor(Cursor.CLOSED_HAND);
        };

        // Register the onMouseDragged event listener if the provided conditional returns true
        mouseTracker.registerOnMousePressedEventHandler(event -> {
            // Check if we are allowed to drag in the first place
            if (!conditional.apply(event) || ModelCanvas.edgeIsBeingDrawn()) return;

            hasDragged[0] = false;

            dragXOffset[0] = subject.xProperty().get() - event.getX();
            dragYOffset[0] = subject.yProperty().get() - event.getY();

            // For children of a draggable parent, update the offset from the parent
            final LocationAware parent = findAncestor(subject);
            if (parent != null) {
                parentXOffset[0] = subject.xProperty().get() - parent.xProperty().get();
                parentYOffset[0] = subject.yProperty().get() - parent.yProperty().get();
            }
<commit_msg>Fix a bug where locations were not bound correctly when on the limit of a component<commit_after>package SW9.utility.helpers;

import SW9.model_canvas.ModelCanvas;
import SW9.utility.UndoRedoStack;
import SW9.utility.mouse.MouseTracker;
import javafx.beans.binding.NumberBinding;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;

import java.util.function.Function;
import java.util.function.Supplier;

public class DragHelper {

    public static <T extends Node & MouseTrackable> void makeDraggable(final T subject) {
        makeDraggable(subject, mouseEvent -> true);
    }

    public static <T extends Node & MouseTrackable> void makeDraggable(final T subject, final Function<MouseEvent, Boolean> conditional) {
        makeDraggable(subject, conditional, null);
    }

    public static <T extends Node & MouseTrackable> void makeDraggable(final T subject, final Function<MouseEvent, Boolean> conditional, final Supplier<Bounds> boundsSupplier) {
        final MouseTracker mouseTracker = subject.getMouseTracker();

        // The offset from the mouse
        final double[] dragXOffset = {0d};
        final double[] dragYOffset = {0d};

        // The offset from the draggable parent, used to undo
        final double[] parentXOffset = {0d};
        final double[] parentYOffset = {0d};

        // Variables to redo the drag later on
        final NumberBinding[] newXBinding = {null};
        final NumberBinding[] newYBinding = {null};
        final double[] newXValue = {0d};
        final double[] newYValue = {0d};

        final boolean[] hasDragged = {false};

        final EventHandler<MouseEvent> onMouseDragged = event -> {
            // Stop propagation of this event
            event.consume();

            // Check if we are allowed to drag in the first place
            if (!conditional.apply(event) || ModelCanvas.edgeIsBeingDrawn()) return;

            // Get the bounds (must be inside the lambda, because bounds might have changed from since we last moved the subject)
            final Bounds[] bounds = {null};
            if (boundsSupplier != null) {
                bounds[0] = boundsSupplier.get();
            }

            hasDragged[0] = true;

            // The location of the mouse (added with the relative to the subject)
            double x = event.getX() + dragXOffset[0];
            double y = event.getY() + dragYOffset[0];

            // Make coordinates snap to the grip on the canvas
            x -= x % ModelCanvas.GRID_SIZE - (ModelCanvas.GRID_SIZE / 2);
            y -= y % ModelCanvas.GRID_SIZE - (ModelCanvas.GRID_SIZE / 2);

            // If the subject has its x property bound have a parent where we can get the xProperty as well
            if (subject.xProperty().isBound()) {
                final LocationAware parent = findAncestor(subject);
                // Bind the x property of the subject to the value of the mouse event relative to the x property of the parent
                newXBinding[0] = parent.xProperty().add(x - parent.xProperty().get());
                if (bounds[0] != null && !bounds[0].contains((Double) newXBinding[0].getValue(), bounds[0].getMinY())) {
                    if ((double) newXBinding[0].getValue() > bounds[0].getMaxX()) {
                        newXBinding[0] = newXBinding[0].subtract(x - bounds[0].getMaxX());
                    } else {
                        newXBinding[0] = newXBinding[0].subtract(x - bounds[0].getMinX());
                    }
                }
                subject.xProperty().bind(newXBinding[0]);
            } else {
                // Update the x property value to the value of the mouse
                newXValue[0] = x;
                subject.xProperty().setValue(x);
            }
            // If the subject has its y property bound have a parent where we can get the yProperty as well
            if (subject.yProperty().isBound()) {
                final LocationAware parent = findAncestor(subject);
                // Bind the y property of the subject to the value of the mouse event relative to the y property of the parent
                newYBinding[0] = parent.yProperty().add(y - parent.yProperty().get());
                if (bounds[0] != null && !bounds[0].contains(bounds[0].getMinX(), (Double) newYBinding[0].getValue())) {
                    if ((double) newYBinding[0].getValue() > bounds[0].getMaxY()) {
                        newYBinding[0] = newYBinding[0].subtract(y - bounds[0].getMaxY());
                    } else {
                        newYBinding[0] = newYBinding[0].subtract(y - bounds[0].getMinY());
                    }
                }
                subject.yProperty().bind(newYBinding[0]);
            } else {
                // Update the y property value to the value of the mouse
                newYValue[0] = y;
                subject.yProperty().setValue(y);
            }

            subject.setCursor(Cursor.CLOSED_HAND);
        };

        // Register the onMouseDragged event listener if the provided conditional returns true
        mouseTracker.registerOnMousePressedEventHandler(event -> {
            // Check if we are allowed to drag in the first place
            if (!conditional.apply(event) || ModelCanvas.edgeIsBeingDrawn()) return;

            hasDragged[0] = false;

            dragXOffset[0] = subject.xProperty().get() - event.getX();
            dragYOffset[0] = subject.yProperty().get() - event.getY();

            // For children of a draggable parent, update the offset from the parent
            final LocationAware parent = findAncestor(subject);
            if (parent != null) {
                parentXOffset[0] = subject.xProperty().get() - parent.xProperty().get();
                parentYOffset[0] = subject.yProperty().get() - parent.yProperty().get();
            }

{'fraction_non_alphanumeric': 0.10767023879841364, 'fraction_numerical': 0.008944392878238124, 'mean_word_length': 2.163063784360822, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3394824', 'n_tokens_mistral': 3206, 'n_tokens_neox': 3095, 'n_words': 924}