Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Ensure immovable blocks are considered during workspace tidying #8550

Conversation

BenHenning
Copy link
Contributor

@BenHenning BenHenning commented Aug 21, 2024

The basics

The details

Resolves

Fixes #6889

Proposed Changes

This PR introduces a fix for #6889 (WorkspaceSvg.cleanUp) when a workspace contains an immovable block. Previously, immovable blocks were ignored in cleanUp which could lead to situations where movable blocks were stacked on top of the immovable blocks. The updated algorithm addresses this.

The old algorithm was essentially the following steps:

  • Sort top-level blocks first by their y value then by their x (per getTopBlocks and Workspace's sorting logic).
  • Position the first movable block at (0, 0).
  • For each subsequent block:
    • If it's immovable, skip it.
    • If it's movable, position it at the previous block's y coordinate plus its height plus a minimum height spacing defined by the renderer's MIN_BLOCK_HEIGHT property. Also, left-align the block at an x value of 0.

The updated algorithm augments this by considering any immovable blocks that the new block's position might intersect with (by using Rect's intersects method), as so:

  • Sort the top-level blocks in the same way before.
  • Split the list of blocks into movable and immovable blocks.
  • For each immovable block, compute its bounds Rect (to be used later).
  • For each movable block, in order, compute its new position:
    • If it's the first block, assume a position of (0, 0). If not, assume it to be (0, y) where y is the previous block's position plus the previous block's height plus the minimum block spacing (as described above).
    • Enumerate all immovable block bounds and verify whether the block's new position would intersect with any of them. If it would, recompute y in the same way as the previous step except use the conflicting immovable block's position and size, rather than the previous movable block.
    • Repeat the last step until the new position no longer conflicts with any immovable blocks.

NOTE:

This PR is also renaming WorkspaceSvg.cleanUp to WorkspaceSvg.tidyUp since 'clean up' is an overloaded term in the codebase and generally means "deinitialize." This PR does not rename the context menu item since cleaning up the workspace has a different context for the user and probably makes equal sense to 'tidy' (so there wasn't an obvious reason to change it other than to keep the two aligned).

This has been reverted after a discussion with the team--the preference is to avoid unnecessary code changes and this rename has few benefits.

Reason for Changes

Trying to tidy up the workspace without considering immovable blocks leads to undesirable results. See previous behavior:

Screen.recording.2024-08-21.1.42.28.PM.webm

With the changes, the new behavior is:

Screen.recording.2024-08-21.1.40.37.PM.webm

This is a much better user experience. Note that the above was demoed by importing the following JSON into a local Blockly playground:

{
  "blocks": {
    "languageVersion": 0,
    "blocks": [
      {
        "type": "math_number",
        "id": "block1",
        "x": 1,
        "y": 2,
        "fields": {
          "NUM": 1
        }
      },
      {
        "type": "math_number",
        "id": "block2",
        "x": 10,
        "y": 20,
        "movable": false,
        "fields": {
          "NUM": 2
        }
      },
      {
        "type": "math_number",
        "id": "block3",
        "x": 2,
        "y": 30,
        "fields": {
          "NUM": 3
        }
      },
      {
        "type": "controls_repeat_ext",
        "id": "block4",
        "x": 3,
        "y": 40,
        "inputs": {
          "TIMES": {
            "shadow": {
              "type": "math_number",
              "fields": {
                "NUM": 10
              }
            }
          },
          "DO": {
            "block": {
              "type": "controls_if",
              "inputs": {
                "IF0": {
                  "block": {
                    "type": "logic_boolean",
                    "fields": {
                      "BOOL": "TRUE"
                    }
                  }
                },
                "DO0": {
                  "block": {
                    "type": "text_print",
                    "inputs": {
                      "TEXT": {
                        "shadow": {
                          "type": "text",
                          "fields": {
                            "TEXT": "abc"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      {
        "type": "math_number",
        "id": "block5",
        "x": 20,
        "y": 200,
        "movable": false,
        "fields": {
          "NUM": 5
        }
      }
    ]
  }
}

Test Coverage

cleanUp had no functional tests, so a bunch were added (including for verifying existing behaviors). All of this function's new tests passed without the algorithmic changes except for the test "multiple block types immovable blocks are not moved" (which was verified to fail, as expected, without the algorithmic fixes).

Separately, Rect had some additional functionality and documentation added, along with an entire new test suite meant to thoroughly test all aspects of the class (since it plays a pivotal role in the new functionality, plus a bunch of other existing functionality throughout Blockly core).

Documentation

It doesn't seem any documentation changes are needed at this time since the fix was entirely infrastructural and implementation-specific. Since this is a public API function, it's certainly possible some documentation work will be needed.

Additional Information

The needs of cleanUp functional changes and its tests led to needing a bounding box class. This was added before Rect was discovered, and its intersection algorithm was independently derived. Rect's own intersection code is actually replaced in this PR with the derived version (the same logic, just inverted) with some documentation to logically explain why it works to help any future readers who come across it.

Separately, the workspace tests prefer to use JSON for block initialization vs. direct API access. This seems to be the recommended way to approach such test condition arrangement after discussions with other Blockly team members.

At a high-level, this change ensures that cleaning up a workspace
doesn't move blocks in a way that overlaps with immovable blocks. It
also adds missing testing coverage for both Rect (used for bounding box
calculations during workspace cleanup) and WorkspaceSvg (for verifying
the updated clean up functionality).

This also renames the clean up function to be 'tidyUp' since that better
suits what's happening (as opposed to other clean-up routines which are
actually deinitializing objects).
@github-actions github-actions bot added the PR: fix Fixes a bug label Aug 21, 2024
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome! It looks like this is your first pull request in Blockly, so here are a couple of tips:

  • You can find tips about contributing to Blockly and how to validate your changes on our developer site.
  • All contributors must sign the Google Contributor License Agreement (CLA). If the google-cla bot leaves a comment on this PR, make sure you follow the instructions.
  • We use conventional commits to make versioning the package easier. Make sure your commit message is in the proper format or learn how to fix it.
  • If any of the other checks on this PR fail, you can click on them to learn why. It might be that your change caused a test failure, or that you need to double-check the style guide.
    Thank you for opening this PR! A member of the Blockly team will review it soon.

Copy link
Contributor Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-reviewed changes.

tests/mocha/rect_test.js Outdated Show resolved Hide resolved
Copy link
Contributor Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-reviewed test rename.

@github-actions github-actions bot added PR: fix Fixes a bug and removed PR: fix Fixes a bug labels Aug 22, 2024
@BenHenning
Copy link
Contributor Author

Looks like this is now ready for review.

@BenHenning BenHenning marked this pull request as ready for review August 22, 2024 18:29
@BenHenning BenHenning requested a review from a team as a code owner August 22, 2024 18:29
@BenHenning BenHenning requested a review from gonfunko August 22, 2024 18:29
@BenHenning
Copy link
Contributor Author

NB: Comments should be limited to 80 characters (ES lint doesn't catch this).

@BenHenning BenHenning assigned BenHenning and unassigned gonfunko Aug 27, 2024
Copy link
Contributor Author

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-reviewed changes renaming back to 'cleanUp'.

@BenHenning BenHenning assigned gonfunko and unassigned BenHenning Sep 3, 2024
@github-actions github-actions bot added PR: fix Fixes a bug and removed PR: fix Fixes a bug labels Sep 3, 2024
@BenHenning
Copy link
Contributor Author

@gonfunko could you PTAL per latest changes and let me know if the PR still looks good to you?

@BenHenning
Copy link
Contributor Author

Thanks @gonfunko!

@BenHenning BenHenning merged commit 6acc583 into google:develop Sep 5, 2024
8 checks passed
@BenHenning BenHenning deleted the ensure-immovable-blocks-are-considered-during-workspace-tidying branch September 5, 2024 20:40
@mikeharv
Copy link
Contributor

mikeharv commented Sep 6, 2024

Thanks so much for this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: fix Fixes a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WorkspaceSvg.cleanUp() method doesn't account for immovable blocks
3 participants