{"action":"created","comment":{"url":"https://api.github.com/repos/wandernauta/viskell/pulls/comments/46823307","id":46823307,"diff_hunk":"@@ -0,0 +1,230 @@\n+package nl.utwente.viskell.ui.components;\n+\n+import java.util.ArrayList;\n+import java.util.Collections;\n+import java.util.HashSet;\n+import java.util.List;\n+import java.util.Optional;\n+import java.util.Set;\n+\n+import javafx.fxml.FXML;\n+import javafx.geometry.BoundingBox;\n+import javafx.scene.layout.BorderPane;\n+import javafx.scene.layout.Pane;\n+import javafx.scene.paint.Color;\n+import javafx.scene.shape.Polygon;\n+import nl.utwente.viskell.haskell.expr.Case;\n+import nl.utwente.viskell.haskell.expr.ConstructorBinder;\n+import nl.utwente.viskell.haskell.expr.Expression;\n+import nl.utwente.viskell.haskell.expr.LetExpression;\n+import nl.utwente.viskell.haskell.type.TypeScope;\n+import nl.utwente.viskell.ui.ComponentLoader;\n+import nl.utwente.viskell.ui.DragContext;\n+\n+/**\n+ * A single alternative within a ChoiceBlock\n+ *\n+ */\n+public class Lane extends BorderPane implements BlockContainer, ComponentLoader {\n+    \n+    /** The argument anchors of this alternative */\n+    protected List<BinderAnchor> arguments;\n+    \n+    /** The result anchor of this alternative */\n+    protected ResultAnchor result;\n+\n+    /** Whether the anchor types are fresh*/\n+    protected boolean freshAnchorTypes;\n+    \n+    /** Status of change updating process in this block. */\n+    protected boolean firstPhaseInProgress;\n+    \n+    /** Status of change updating process in this block. */\n+    protected boolean finalPhaseInProgress;\n+    \n+    /** The wrapper to which this alternative belongs */\n+    protected ChoiceBlock parent;\n+    \n+    /** The draggable resizer in the bottom right corner */\n+    private Polygon resizer;\n+\n+    /** The container Node for binder anchors */\n+    @FXML protected Pane argumentSpace;\n+    \n+    /** The resizable area on which blocks can be placed */\n+    @FXML protected Pane guardSpace;\n+    \n+    /** The container Node for result anchors */\n+    @FXML protected Pane resultSpace;\n+\n+    /** A set of blocks that belong to this container */\n+    protected Set<Block> attachedBlocks;\n+\n+    public Lane(ChoiceBlock wrapper) {\n+        super();\n+        loadFXML(\"Lane\");\n+        parent = wrapper;\n+        arguments = new ArrayList<>();\n+        result = new ResultAnchor(this, wrapper, Optional.empty());\n+        attachedBlocks = new HashSet<>();\n+        \n+        argumentSpace.getChildren().addAll(arguments);\n+        resultSpace.getChildren().add(result);\n+        setupResizer();\n+    }\n+\n+    /**\n+     * Returns the pattern and guard expression for this lane as well as a set of required blocks.\n+     * \n+     * Firstly, the expression is generated from the result anchor.\n+     * Secondly, the expression is extended with bottom-most blocks within this lane.\n+     * Bottom-most blocks are *assumed* to be either deconstructors or expressions resulting in a Bool.\n+     * \n+     * @return a pair containing this lane's Alternative and a set of required blocks\n+     */\n+    public Pair<Case.Alternative,Set<Block>> getAlternative() {\n+        Pair<Expression, Set<Block>> pair = result.getLocalExpr();\n+        LetExpression guards = new LetExpression(pair.a, true);\n+        Set<Block> surroundingBlocks = pair.b;\n+        result.extendExprGraph(guards, this, surroundingBlocks);\n+        \n+        attachedBlocks.stream().filter(Block::isBottomMost).forEach(block -> {\n+            if (block instanceof MatchBlock) {\n+                guards.addLetBinding(((MatchBlock)block).getPrimaryBinder(), block.getAllInputs().get(0).getFullExpr());\n+            }\n+            else {\n+                block.getAllOutputs().forEach(anchor -> {\n+                    guards.addLetBinding(new ConstructorBinder(\"True\", Collections.EMPTY_LIST), anchor.getVariable());\n+                    anchor.extendExprGraph(guards, this, surroundingBlocks);\n+                });\n+            }\n+            block.extendExprGraph(guards, this, surroundingBlocks);\n+        });\n+        \n+        return new Pair<>(new Case.Alternative(new ConstructorBinder(\"()\", Collections.EMPTY_LIST), guards), surroundingBlocks);\n+    }\n+\n+    /** Returns the result anchor of this Lane */\n+    public ResultAnchor getOutput() {\n+        return result;\n+    }\n+\n+    @Override\n+    public void refreshAnchorTypes() {\n+        // refresh anchor types only once at the start\n+        if (!firstPhaseInProgress && !freshAnchorTypes) {\n+            freshAnchorTypes = true;\n+            \n+            TypeScope scope = new TypeScope();\n+            arguments.forEach(argument -> argument.refreshType(scope));\n+            result.refreshAnchorType(scope);\n+        }\n+    }\n+    \n+    @Override\n+    public final void handleConnectionChanges(boolean finalPhase) {\n+        // avoid doing extra work and infinite recursion\n+        if ((!finalPhase && !firstPhaseInProgress) || (finalPhase && !finalPhaseInProgress)) {\n+            if (!finalPhase) {\n+                // in first phase ensure that anchor types are refreshed if propagating from the outside\n+                refreshAnchorTypes();\n+\n+                firstPhaseInProgress = true;\n+                finalPhaseInProgress = false;\n+            }\n+            else {\n+                firstPhaseInProgress = false;\n+                finalPhaseInProgress = true;\n+            }\n+\n+            freshAnchorTypes = false;\n+            \n+            // first propagate up from the result anchor\n+            result.getConnection().ifPresent(c -> c.handleConnectionChangesUpwards(finalPhase));\n+            \n+            // also propagate in from above in case the lane is partially connected \n+            arguments.forEach(argument -> {\n+                argument.getOppositeAnchors().forEach(anchor -> {\n+                    anchor.handleConnectionChanges(finalPhase);\n+                    // take the type of argument connections into account even if the connected block is being processed\n+                    anchor.getConnection().ifPresent(connection -> connection.handleConnectionChangesUpwards(finalPhase));\n+                });\n+            });\n+    \n+            // propagate internal type changes outwards\n+            parent.handleConnectionChanges(finalPhase);\n+        }\n+    }\n+\n+    /** Called when the VisualState changed. */\n+    public void invalidateVisualState() {\n+        // TODO update anchors when they get a type label       \n+    }\n+    \n+    /** Add and initializes a resizer element to this block */\n+    private void setupResizer() {\n+        resizer = new Polygon();\n+        resizer.getPoints().addAll(new Double[]{20.0, 20.0, 20.0, 0.0, 0.0, 20.0});\n+        resizer.setFill(Color.BLUE);\n+\n+        resizer.setManaged(false);\n+        this.getChildren().add(resizer);\n+        resizer.relocate(300-20, 400-20);","path":"Code/src/main/java/nl/utwente/viskell/ui/components/Lane.java","position":172,"original_position":172,"commit_id":"b359498bfd7a8c3ade0ddff865c0a84cc61c9ec3","original_commit_id":"b359498bfd7a8c3ade0ddff865c0a84cc61c9ec3","user":{"login":"wandernauta","id":126832,"avatar_url":"https://avatars.githubusercontent.com/u/126832?v=3","gravatar_id":"","url":"https://api.github.com/users/wandernauta","html_url":"https://github.com/wandernauta","followers_url":"https://api.github.com/users/wandernauta/followers","following_url":"https://api.github.com/users/wandernauta/following{/other_user}","gists_url":"https://api.github.com/users/wandernauta/gists{/gist_id}","starred_url":"https://api.github.com/users/wandernauta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wandernauta/subscriptions","organizations_url":"https://api.github.com/users/wandernauta/orgs","repos_url":"https://api.github.com/users/wandernauta/repos","events_url":"https://api.github.com/users/wandernauta/events{/privacy}","received_events_url":"https://api.github.com/users/wandernauta/received_events","type":"User","site_admin":false},"body":"This is copied from DefinitionBlock - might be worth extracting or moving to a common superclass.","created_at":"2015-12-07T14:04:45Z","updated_at":"2015-12-07T14:04:45Z","html_url":"https://github.com/wandernauta/viskell/pull/298#discussion_r46823307","pull_request_url":"https://api.github.com/repos/wandernauta/viskell/pulls/298","_links":{"self":{"href":"https://api.github.com/repos/wandernauta/viskell/pulls/comments/46823307"},"html":{"href":"https://github.com/wandernauta/viskell/pull/298#discussion_r46823307"},"pull_request":{"href":"https://api.github.com/repos/wandernauta/viskell/pulls/298"}}},"pull_request":{"url":"https://api.github.com/repos/wandernauta/viskell/pulls/298","id":52842308,"html_url":"https://github.com/wandernauta/viskell/pull/298","diff_url":"https://github.com/wandernauta/viskell/pull/298.diff","patch_url":"https://github.com/wandernauta/viskell/pull/298.patch","issue_url":"https://api.github.com/repos/wandernauta/viskell/issues/298","number":298,"state":"open","locked":false,"title":"Case block and containers","user":{"login":"Flumble","id":904938,"avatar_url":"https://avatars.githubusercontent.com/u/904938?v=3","gravatar_id":"","url":"https://api.github.com/users/Flumble","html_url":"https://github.com/Flumble","followers_url":"https://api.github.com/users/Flumble/followers","following_url":"https://api.github.com/users/Flumble/following{/other_user}","gists_url":"https://api.github.com/users/Flumble/gists{/gist_id}","starred_url":"https://api.github.com/users/Flumble/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Flumble/subscriptions","organizations_url":"https://api.github.com/users/Flumble/orgs","repos_url":"https://api.github.com/users/Flumble/repos","events_url":"https://api.github.com/users/Flumble/events{/privacy}","received_events_url":"https://api.github.com/users/Flumble/received_events","type":"User","site_admin":false},"body":"Changes:\r\n  - Preliminary case block added to the menu consisting of a surrounding block with an output anchor and 2 alternatives with a result anchor (adding and removing alternatives is supported by the block)\r\n  - Alternatives in a case block generate an expression in the form of a pattern, a pattern guard and a body (though in its current form only the guard is populated dynamically and the body is populated by the result anchor)\r\n  - Blocks can attach themselves to a container and expression building is limited accordingly\r\n  - Expression building now returns both the expression and a set of required blocks for that expression","created_at":"2015-12-07T13:08:53Z","updated_at":"2015-12-07T14:04:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"55cb15fa0c53d85656631e45c44956235cf6fdea","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/wandernauta/viskell/pulls/298/commits","review_comments_url":"https://api.github.com/repos/wandernauta/viskell/pulls/298/comments","review_comment_url":"https://api.github.com/repos/wandernauta/viskell/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wandernauta/viskell/issues/298/comments","statuses_url":"https://api.github.com/repos/wandernauta/viskell/statuses/b359498bfd7a8c3ade0ddff865c0a84cc61c9ec3","head":{"label":"wandernauta:case-block","ref":"case-block","sha":"b359498bfd7a8c3ade0ddff865c0a84cc61c9ec3","user":{"login":"wandernauta","id":126832,"avatar_url":"https://avatars.githubusercontent.com/u/126832?v=3","gravatar_id":"","url":"https://api.github.com/users/wandernauta","html_url":"https://github.com/wandernauta","followers_url":"https://api.github.com/users/wandernauta/followers","following_url":"https://api.github.com/users/wandernauta/following{/other_user}","gists_url":"https://api.github.com/users/wandernauta/gists{/gist_id}","starred_url":"https://api.github.com/users/wandernauta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wandernauta/subscriptions","organizations_url":"https://api.github.com/users/wandernauta/orgs","repos_url":"https://api.github.com/users/wandernauta/repos","events_url":"https://api.github.com/users/wandernauta/events{/privacy}","received_events_url":"https://api.github.com/users/wandernauta/received_events","type":"User","site_admin":false},"repo":{"id":30242992,"name":"viskell","full_name":"wandernauta/viskell","owner":{"login":"wandernauta","id":126832,"avatar_url":"https://avatars.githubusercontent.com/u/126832?v=3","gravatar_id":"","url":"https://api.github.com/users/wandernauta","html_url":"https://github.com/wandernauta","followers_url":"https://api.github.com/users/wandernauta/followers","following_url":"https://api.github.com/users/wandernauta/following{/other_user}","gists_url":"https://api.github.com/users/wandernauta/gists{/gist_id}","starred_url":"https://api.github.com/users/wandernauta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wandernauta/subscriptions","organizations_url":"https://api.github.com/users/wandernauta/orgs","repos_url":"https://api.github.com/users/wandernauta/repos","events_url":"https://api.github.com/users/wandernauta/events{/privacy}","received_events_url":"https://api.github.com/users/wandernauta/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wandernauta/viskell","description":"Visual programming meets Haskell","fork":false,"url":"https://api.github.com/repos/wandernauta/viskell","forks_url":"https://api.github.com/repos/wandernauta/viskell/forks","keys_url":"https://api.github.com/repos/wandernauta/viskell/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wandernauta/viskell/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wandernauta/viskell/teams","hooks_url":"https://api.github.com/repos/wandernauta/viskell/hooks","issue_events_url":"https://api.github.com/repos/wandernauta/viskell/issues/events{/number}","events_url":"https://api.github.com/repos/wandernauta/viskell/events","assignees_url":"https://api.github.com/repos/wandernauta/viskell/assignees{/user}","branches_url":"https://api.github.com/repos/wandernauta/viskell/branches{/branch}","tags_url":"https://api.github.com/repos/wandernauta/viskell/tags","blobs_url":"https://api.github.com/repos/wandernauta/viskell/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wandernauta/viskell/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wandernauta/viskell/git/refs{/sha}","trees_url":"https://api.github.com/repos/wandernauta/viskell/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wandernauta/viskell/statuses/{sha}","languages_url":"https://api.github.com/repos/wandernauta/viskell/languages","stargazers_url":"https://api.github.com/repos/wandernauta/viskell/stargazers","contributors_url":"https://api.github.com/repos/wandernauta/viskell/contributors","subscribers_url":"https://api.github.com/repos/wandernauta/viskell/subscribers","subscription_url":"https://api.github.com/repos/wandernauta/viskell/subscription","commits_url":"https://api.github.com/repos/wandernauta/viskell/commits{/sha}","git_commits_url":"https://api.github.com/repos/wandernauta/viskell/git/commits{/sha}","comments_url":"https://api.github.com/repos/wandernauta/viskell/comments{/number}","issue_comment_url":"https://api.github.com/repos/wandernauta/viskell/issues/comments{/number}","contents_url":"https://api.github.com/repos/wandernauta/viskell/contents/{+path}","compare_url":"https://api.github.com/repos/wandernauta/viskell/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wandernauta/viskell/merges","archive_url":"https://api.github.com/repos/wandernauta/viskell/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wandernauta/viskell/downloads","issues_url":"https://api.github.com/repos/wandernauta/viskell/issues{/number}","pulls_url":"https://api.github.com/repos/wandernauta/viskell/pulls{/number}","milestones_url":"https://api.github.com/repos/wandernauta/viskell/milestones{/number}","notifications_url":"https://api.github.com/repos/wandernauta/viskell/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wandernauta/viskell/labels{/name}","releases_url":"https://api.github.com/repos/wandernauta/viskell/releases{/id}","created_at":"2015-02-03T13:04:49Z","updated_at":"2015-11-05T14:25:30Z","pushed_at":"2015-12-07T13:08:53Z","git_url":"git://github.com/wandernauta/viskell.git","ssh_url":"git@github.com:wandernauta/viskell.git","clone_url":"https://github.com/wandernauta/viskell.git","svn_url":"https://github.com/wandernauta/viskell","homepage":"","size":6020,"stargazers_count":2,"watchers_count":2,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":33,"forks":0,"open_issues":33,"watchers":2,"default_branch":"master"}},"base":{"label":"wandernauta:master","ref":"master","sha":"8a6ffc90a52ad18b2a718fce3e6c6613aa432ab4","user":{"login":"wandernauta","id":126832,"avatar_url":"https://avatars.githubusercontent.com/u/126832?v=3","gravatar_id":"","url":"https://api.github.com/users/wandernauta","html_url":"https://github.com/wandernauta","followers_url":"https://api.github.com/users/wandernauta/followers","following_url":"https://api.github.com/users/wandernauta/following{/other_user}","gists_url":"https://api.github.com/users/wandernauta/gists{/gist_id}","starred_url":"https://api.github.com/users/wandernauta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wandernauta/subscriptions","organizations_url":"https://api.github.com/users/wandernauta/orgs","repos_url":"https://api.github.com/users/wandernauta/repos","events_url":"https://api.github.com/users/wandernauta/events{/privacy}","received_events_url":"https://api.github.com/users/wandernauta/received_events","type":"User","site_admin":false},"repo":{"id":30242992,"name":"viskell","full_name":"wandernauta/viskell","owner":{"login":"wandernauta","id":126832,"avatar_url":"https://avatars.githubusercontent.com/u/126832?v=3","gravatar_id":"","url":"https://api.github.com/users/wandernauta","html_url":"https://github.com/wandernauta","followers_url":"https://api.github.com/users/wandernauta/followers","following_url":"https://api.github.com/users/wandernauta/following{/other_user}","gists_url":"https://api.github.com/users/wandernauta/gists{/gist_id}","starred_url":"https://api.github.com/users/wandernauta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wandernauta/subscriptions","organizations_url":"https://api.github.com/users/wandernauta/orgs","repos_url":"https://api.github.com/users/wandernauta/repos","events_url":"https://api.github.com/users/wandernauta/events{/privacy}","received_events_url":"https://api.github.com/users/wandernauta/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/wandernauta/viskell","description":"Visual programming meets Haskell","fork":false,"url":"https://api.github.com/repos/wandernauta/viskell","forks_url":"https://api.github.com/repos/wandernauta/viskell/forks","keys_url":"https://api.github.com/repos/wandernauta/viskell/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wandernauta/viskell/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wandernauta/viskell/teams","hooks_url":"https://api.github.com/repos/wandernauta/viskell/hooks","issue_events_url":"https://api.github.com/repos/wandernauta/viskell/issues/events{/number}","events_url":"https://api.github.com/repos/wandernauta/viskell/events","assignees_url":"https://api.github.com/repos/wandernauta/viskell/assignees{/user}","branches_url":"https://api.github.com/repos/wandernauta/viskell/branches{/branch}","tags_url":"https://api.github.com/repos/wandernauta/viskell/tags","blobs_url":"https://api.github.com/repos/wandernauta/viskell/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wandernauta/viskell/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wandernauta/viskell/git/refs{/sha}","trees_url":"https://api.github.com/repos/wandernauta/viskell/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wandernauta/viskell/statuses/{sha}","languages_url":"https://api.github.com/repos/wandernauta/viskell/languages","stargazers_url":"https://api.github.com/repos/wandernauta/viskell/stargazers","contributors_url":"https://api.github.com/repos/wandernauta/viskell/contributors","subscribers_url":"https://api.github.com/repos/wandernauta/viskell/subscribers","subscription_url":"https://api.github.com/repos/wandernauta/viskell/subscription","commits_url":"https://api.github.com/repos/wandernauta/viskell/commits{/sha}","git_commits_url":"https://api.github.com/repos/wandernauta/viskell/git/commits{/sha}","comments_url":"https://api.github.com/repos/wandernauta/viskell/comments{/number}","issue_comment_url":"https://api.github.com/repos/wandernauta/viskell/issues/comments{/number}","contents_url":"https://api.github.com/repos/wandernauta/viskell/contents/{+path}","compare_url":"https://api.github.com/repos/wandernauta/viskell/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wandernauta/viskell/merges","archive_url":"https://api.github.com/repos/wandernauta/viskell/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wandernauta/viskell/downloads","issues_url":"https://api.github.com/repos/wandernauta/viskell/issues{/number}","pulls_url":"https://api.github.com/repos/wandernauta/viskell/pulls{/number}","milestones_url":"https://api.github.com/repos/wandernauta/viskell/milestones{/number}","notifications_url":"https://api.github.com/repos/wandernauta/viskell/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wandernauta/viskell/labels{/name}","releases_url":"https://api.github.com/repos/wandernauta/viskell/releases{/id}","created_at":"2015-02-03T13:04:49Z","updated_at":"2015-11-05T14:25:30Z","pushed_at":"2015-12-07T13:08:53Z","git_url":"git://github.com/wandernauta/viskell.git","ssh_url":"git@github.com:wandernauta/viskell.git","clone_url":"https://github.com/wandernauta/viskell.git","svn_url":"https://github.com/wandernauta/viskell","homepage":"","size":6020,"stargazers_count":2,"watchers_count":2,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":33,"forks":0,"open_issues":33,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wandernauta/viskell/pulls/298"},"html":{"href":"https://github.com/wandernauta/viskell/pull/298"},"issue":{"href":"https://api.github.com/repos/wandernauta/viskell/issues/298"},"comments":{"href":"https://api.github.com/repos/wandernauta/viskell/issues/298/comments"},"review_comments":{"href":"https://api.github.com/repos/wandernauta/viskell/pulls/298/comments"},"review_comment":{"href":"https://api.github.com/repos/wandernauta/viskell/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wandernauta/viskell/pulls/298/commits"},"statuses":{"href":"https://api.github.com/repos/wandernauta/viskell/statuses/b359498bfd7a8c3ade0ddff865c0a84cc61c9ec3"}}}}