Skip to content
New issue

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

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

Already on GitHub? # to your account

Add context menu items to facilitate editing #132

Open
5 of 8 tasks
cpcallen opened this issue Nov 15, 2024 · 11 comments
Open
5 of 8 tasks

Add context menu items to facilitate editing #132

cpcallen opened this issue Nov 15, 2024 · 11 comments
Assignees

Comments

@cpcallen
Copy link
Contributor

cpcallen commented Nov 15, 2024

Add the following items to the context menus for blocks, with the the given keyboard shortcuts:

Add the following item to the context menu for unconnected next and input connections, as well as when the cursor is visiting the workspace:

  • Place block (same as replace block, above): place a new block at this location using the marker workflow.

The names given above are not necessarily intended to be the final English names for the given items, merely descriptive.

@cpcallen
Copy link
Contributor Author

@rachel-fenichel: as I noted in the discussion with Kirsty, I think "Insert" should be the primary shortcut for adding blocks, and I'm not sure that if we have insert we need replace.

@kmcnaught
Copy link

kmcnaught commented Jan 29, 2025

Is this a question about naming, shortcut key choice, or functionality? Or all three?

If you are at a prev/next connection then "insert" would add a new block in the current location.

If you were at an in/out connection (not a block) then an action called "insert" might replace the currently-connected block(s) with the newly selected one. Are there any geras-style platforms where it might be appropriate/meaningful to insert a block between in/out as an extra block, without replacing anything? I don't think this would ever be the case in MakeCode.

If you were at a [single cursor location that collapses a block and its out connection] then I was imagining an action called "replace" would replace the currently-connected block(s) with the newly selected one.

What we can't rely on is using "delete" followed by "insert" to work for reporter blocks as an alternative for "replace", since deleting might (nearly always in MakeCode) leave you with a shadow block. So for blocks connected at an in/out connection, there needs to be an action that is semantically equivalent to "replace" even if you decide it's unambiguous to call it "insert" (I think it's much easier to argue this at an in/out connection than at a "collapsed single location".)

For instance, if we collapse to a single cursor location (as per Matt's demo) then in the below situation, I would expect a context menu to give me a single action for "insert/replace" that replaces the block.
screenshot of pause blocks, one with shadow block and one with variable

I can see an argument for keeping the naming/shortcut keys equivalent for these actions, and I can't see a situation where "Insert" and "Replace" would be 2 different valid actions, unless there's some geras-style applications where inserting in the middle of a horizontal stack of blocks would be desirable

@rachel-fenichel
Copy link
Contributor

We discussed this live today with @cpcallen, @microbit-matt-hillsdon, Lucy, Emma, and Robert. I think our conclusions were:

  • All of the insertion/replacement flows you described need to be possible (so we seem to agree about required functionality)
  • The name of the action, as shown to the user, may be different in different places (e.g. insert vs replace)
  • Replacement is more likely in horizontal cases, while insertion is more likely in vertical cases
  • Christopher objects to having both "Insert (above)" and "Replace" on a stack block, finding them redundant
  • Many of these cases are handled in core Blockly in the dragging logic, and Christopher and Rachel think we should match that logic where possible
    • Rachel also wants this because it means free functionality by just calling connect

In #196 I implemented the necessary logic for replacing a reporter block (block with an output) with an appropriate block from the flyout/toolbox.

I agree that in your case above, the context menu has an insert/replace action.

@rachel-fenichel
Copy link
Contributor

Are there any geras-style platforms where it might be appropriate/meaningful to insert a block between in/out as an extra block, without replacing anything? I don't think this would ever be the case in MakeCode.

Yes! And I can make it happen in MakeCode too. This feature is called "healing a stack" or "splicing". It's implemented in unplugFromRow and unplugFromStack in core Blockly.

Examples

In the advanced Blockly playground, with our basic blocks:
Image

And the same thing in MakeCode:

Image

Explanation

Situations that trigger this:

  • You have a parent block A with a single value input (print block)
    Image

  • There is a connected block B with a single value output (number block: 3.14)
    Image

  • There is a block C that has a single value input and a single value output, both of the appropriate type (square root block)
    Image

  • Block C is dragged between blocks A and B

  • When the drag ends, the blocks will be connected horizontally in order (from left to right) A, C, B
    Image

Note that in both cases there is a shadow block D that is initially attached to block C's input. Block D disappears, because block B covers it up.
Image

Other info

You cannot trigger a splice if block C has two value inputs, because the correct operation is ambiguous:

Geras:
Image

Zelos:

Image

You can trigger a splice if block B has two value inputs, because the correct operation is unambiguous:

Geras:

Image

Zelos:
Image

@kmcnaught
Copy link

Ooh. That is what I had pictured in geras, but a bit surprising in MakeCode. Thanks for the examples!

My initial position is that we would expect the same behaviour from a keyboard-triggered "insert/replace" operation as you would get from a mouse drag. Now I understand more I can imagine that sometimes it's going to be a bit awkward if the splicing isn't what was intended. I don't think it changes my views on the core insert/replace flow, just a slightly surprising artefact of existing behaviour.

Do you have any intention to give more control over this, or does it change your views at all?

@rachel-fenichel
Copy link
Contributor

I don't think it changes my views on the core insert/replace flow, just a slightly surprising artefact of existing behaviour.

Same here, especially because it lets us rely on existing (and well-tested) code in core, rather than throwing together a new layer of complex checks.

Please give insertion/replacement for inputs and outputs a try using the T key after #196 and let me know if it feels reasonable.

That change does not address the issues of when insert/replace should be in the context menu or what the text of the insert/replace option should be.

@kmcnaught
Copy link

I've just tried it. The general feel of inserting with 't' is very reasonable and aligned with what I was hoping for.

There's a slight weirdness that you end up with the cursor at the connection (which is usually skipped) after inserting. I don't know if this will lead to any bugs in the context menu etc, or if it's just a cosmetic bug.

I can imagine that once copy/paste is working, this will all feel quite powerful. It would be easy to e.g. remove the sin from the outside of a number block by copying/cutting the child, deleting the parent, and pasting the child in again.

I still don't quite understand the rules around splicing. There's a 30 second video here showing 2 situations where the splicing behaviour is different but I expected the same.

(to clarify - I don't think we should change splicing behaviour for keyboard nav, unless there are bug fixes that apply everywhere - I'm just getting my head around the logic)

@rachel-fenichel
Copy link
Contributor

Yes, that behaviour is consistent with the other behaviour but is also confusing in the zelos case. If we change it for keyboard nav we may also want to change it for mouse. (In which case would file that as a separate bug to figure out the exact conditions for a different behaviour.)

Explanation:

Here's a gif of the same flow with two changes: I turned on the geras renderer and set the theme to the standard Blockly theme, which renders shadow blocks as lighter versions of real blocks, to make it easier to see the differences.

Image

The behaviour is confusing because it relies on the distinction between shadow blocks and real blocks, which is minimal in zelos.

The x + y block is a real block, with two shadow children (1 and 4).

The sin block is a real block with one shadow child (45).

The repeat X times block is a real block with one shadow child (10).

Changing the value in the number block to 123 does not convert it to a real (non-shadow) block. There is a plugin that does convert shadow blocks to real blocks on edit.

When you insert the sin block at the output of the x + y block, it splices because the real x + y block is higher priority than the shadow number block (45) that was already attached to the sin block.

When you insert the sin block at the output of the 123 block it replaces because the shadow 123 is lower priority than the shadow 45 that was already attached to the sin block.

At the end of the gif I navigate to each sin block and delete it. Notice that the 123 comes back for the lower repeat: when a shadow block is obscured, its value is stashed and reapplied if the obscuring block is deleted. That's also why the 10 block reappears as a 10.

@kmcnaught
Copy link

Thanks for the explanation and demo, that makes a lot of sense. I can't help but favour the plugin's behaviour of turning a shadow block into a real block on edit - since that shows intent from the user to make something concrete. Are there situations or applications in which this wouldn't make sense, or previous discussions I can refer back to learn about the competing needs?

There are downstream consequences of this behaviour on copy and paste, which don't make up with my expectations. I would have assumed you'd be able to copy and paste the contents of an oval, like the text in a "write with shadow" block

Screenshot. Write with shadow (item variable). Write with shadow "how are you". The block containing "how are you" is selected.

I would naively argue that these blocks should be real, and draggable, and copyable. If they are not, then we definitely need some user feedback when they try to copy a block, because currently copy will silently fail and you'll end up surprised by pasting the last thing in the copy buffer.

@rachel-fenichel
Copy link
Contributor

The main reason to have shadow blocks is that they are undeletable, so you can never end up with an empty input.

Converting it to a real block on change means that the edited block would get bumped out, instead of obscured, by dragging on a new block.

The issue with not being able to copy them is due to the precondition checks for copying and should be resolvable, so I've added an issue for that.

@rachel-fenichel
Copy link
Contributor

Remaining work not required for testing, so this is now in the "simple editing complete" milestone.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
Status: Todo
Development

No branches or pull requests

3 participants