-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add Entry undo/redo functionality #4251
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really excellent work, thanks so much.
A couple of items about naming inline but it is clear and well laid out, thanks.
One possible bug to be improved - if I "undo" and there are no items left it seems to put the cursor back to the top left, scrolling content if appropriate. I don't think that should happen? |
Hi, glad you like it! I'm not home right now, but when I am I'll be able address these issues and make the necessary changes. Regarding the naming, insert was essentially vim terminology. But I think I'll change it to something like "modifyAction" instead, since that makes a lot more sense. Regarding the bug, that's because the new cursor position is default initialized to 0 and if it isn't an insertAction, it uses that default value instead of just returning. Should be an easy fix. Also, I think it would make sense to expose Undo and Redo as public functions, since you might want that for text editors, for example. |
When the undo stack was empty, the cursor would just jump to position 0 on undo. With this change, undo/redo only changes the cursor position if anything was actually undone or redone.
Alright, I made all the changes you requested + I made Undo/Redo public functions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks excellent, thanks for all the fixes.
Please annotate the new APIs with the version number as commented inline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this. I have a few comments inline.
undoItem := fyne.NewMenuItem("Undo", e.Undo) | ||
redoItem := fyne.NewMenuItem("Redo", e.Redo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How common is it to have undo and redo in the context menu? It seems to me like most applications don't expose it there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QT has undo/redo in the context menu in every text box by default. Also all popular web browsers. GTK apps are the only counter example I can think of. I don't think it's unreasonable to expose it in the context menu.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A possible improvement though would be to only show undo/redo if there is actually anything to undo/redo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A possible improvement though would be to only show undo/redo if there is actually anything to undo/redo
I just implemented that, it was pretty simple. Looks a bit cleaner now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally it would be enable/disable rather than add/remove - having menus be consistent in size and layout makes it easier to navigate them at speed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, it is less cluttered. Also that's how Chromium does it. And if you want to operate at speed, you'll want to use keyboard shortcuts anyway. But your project, your design decisions :)
What's it with the CI checks not passing? Is that my fault? |
There seems to be a bug with the windows / go 1.17 that has impacted all builds in the last 3 days. Multiple projects have noted it - we may need to downgrade the patch version for that build until it's fixed. Not your fault at all! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just 2 types missing the Since line sorry I missed that before.
Otherwise I think it's great - @Jacalz ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing thanks
I'll try to review tomorrow or on Monday. Been a bit busy lately |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @xypwn for a well written PR both in terms of code and the extensive description. Your work is much appreciated. Looks good to me.
Also, congratulations on landing your first PR for Fyne 🥳
Let's gooo! Thank you all! |
So excited this is in - thanks a lot :) v2.5.0 looks great already and it's still 3-4 months away! |
@andydotxyz Can you please share the release plan for these changes? I cannot find them in the master branch. |
It will be added in v2.5.0 |
Exactly right. As you can see we are working towards feature freeze now, but you can use it on @develop branch before then. |
Description:
Implements #436
Checklist:
Notes:
I wrote this independently of #2539.
My implementation is fairly extensible, although currently tied to Entry by name.
It works by keeping track of the changes made by the user, NOT by making snapshots. This makes it more efficient and flexible than the other implementation.
Basic Architecture:
interface entryUndoAction
: Represents a single user interaction. It contains the functionsUndo
andRedo
, which modify the current Entry content to undo/redo that user interaction.interface entryMergeableUndoAction
: Extends entryUndoAction. Contains theTryMerge
method, which allows for merging two actions into one. This is useful because, for example when typing a word, we want to undo that whole word at once, and not have to spamCtrl+Z
for every character.struct entryInsertAction
: ImplementsentryMergeableUndoAction
and represents a string insertion or deletion. It only saves the position and string of the edit, i.e. no snapshots, as mentioned previously. It can merge with itself, but doesn't merge across word boundaries.struct entryUndoStack
: This is the main interface for dealing with the undo/redo system. It has the following methods:Undo
/Redo
: Executes the current undo/redo operation on the current string and returns the new string as well as the executed operation.Add
/MergeOrAdd
: Records the given action, allowing forUndo
/Redo
to be called afterwards.MergeOrAdd
also tries to merge the given action with the undo action already on top of the stack; if it can't merge, it just reverts to callAdd
.Clear
clears all records in the undo stack. This is done after SetText() is called, for example, also meaning that SetText() modifications aren't recorded.Feel free to drop in any suggestions :)