Open aldrinmathew opened 3 years ago
Yes this is definitely a proposal. Just tested on Slack MacOS app and Tab button move focus to another component.
Found a way to accomplish this:
But I agree that there should be two properties on EditableText
and TextField
called something like:
bool acceptTabs
int tabIndentation
And TextField or Editable text should handle wrapping in the Action
/ Shortcuts
widget.
@TimWhiting @pedromassangocode
I tested the implementation by Tim Whiting and it works well. :+1:
However, I reviewed the code and found that it is adding the appropriate number of spaces whenever the user presses Tab key. I have already implemented this in the application that I am developing. Is there anyway that we can add the '\t' character in the text and make it look like multiple spaces? I mean, without replacing the tab with spaces? In theory, we should be able to configure and customise the display of certain characters in the text field. Especially when we consider the possibility that desktop applications developed by flutter might not always be mere "applications", they might be complex enough to be called "software".
I want the user to be able to add the raw tab character (\t) to the text field. And I want to customise the display of the tab character to resemble the equivalent number of spaces chosen by the user. I am developing a text/code editor. I think you get where I am going with this. If a user/programmer presses tab to indent their content/code, and if I write code to replace the indentation with actual whitespace, someone's definitely getting angry. I can easily provide them with an option to replace '\t' with spaces, but that shouldn't be the default behaviour in this case.
@TimWhiting
This is the modified code. This won't run as there is no property called indentSpaceCount for TextField.
Yeah, I agree, the properties should be more like:
As a design note, for accessibility there needs to be a way to unfocus the field that accepts tabs to a larger focus scope to allow moving to a different field. I believe this is typically done by the escape key, but I could be wrong.
@TimWhiting
Exactly, this model looks perfect. And yes, Escape key is usually the way to do it.
Thinking a bit more:
The indentSpaceCount
should probably be in the TextStyle
instead. Which can be specified application wide.
And replaceTabsWithSpaces
should not be a property and users should use a TextInputFormatter
instead to replace \t with whatever so that users can do anything (for example code editors should indent the start of the line the user pressed \t on, and not at the location they pressed it, same for bulleted lists).
So the TextInputFormatters
that should be added would be:
IndentLineFormatter()
--> replaces a \t anywhere in the line with a \t at the beginning of the line
ReplaceTabFormatter(int numSpaces)
--> replaces a \t with numSpaces of plain spaces
Which could be chained to provide both.
Also I forgot in my implementation to add a Shift-tab which would need a
DedentLineFormatter(int numSpaces)
--> replace a \t or numSpaces at the beginning of the line with ''
Edit: But I guess this is where the TextInputFormatters break down, because any time it formats it will remove another \t or spaces until everything is dedented completely. So maybe the Shortcuts / Action framework is really the better fit for handling tab / shift-tab. But we could still use TextInputFormatters to do the job to allow for flexibility for the user to change tabs to whatever they want. But instead of have them in the list of general TextInputFormatters, they should be two properties:
or:
I agree that there should be something like a tabWidth
in the TextStyle, that controls how wide a tab is drawn when rendered, the units should probably be in multiples of the em space of the font. There should be a property on the text field that says whether it handles tabs or not. Replacing tabs with spaces is probably something that should be done after the text is received by the app, since that's highly dependent on the use case (a rich text editor would want tab stops, a code editor might want to start at a particular initial indent before replacing tabs with spaces, etc.)
Note that if a text field handles tabs, then the app is no longer traversable via the keyboard, since as soon as a text field gets focus, it will not allow the focus to leave again when the user presses tab. This is bad for accessibility on all platforms (including mobile platforms), which is why the current implementation always interprets tabs as focus change events. @TimWhiting in your usage of the escape key to enable this, what is the behavior? Does it just jump to the next control? Does Shift-Esc do anything (like go to the previous control)?
We aspire to someday be able to allow people to easily write a code or rich text editor in Flutter, but we're definitely not there yet, and this is one of the areas where we're missing functionality.
I've thought before that there should also be some way to configure all of the text fields in a widget subtree based on the TextInputType
of the field (and maybe allow defining user types for text fields), which would be useful in configuring more complex apps for things like this.
cc @HansMuller
@gspencergoog
I have implemented many major features required for a basic code editor in my application. The application can autosave files and create new files. it supports basic auto-completion. It starts with Dark Mode as the default colour scheme. It can generate a Syntax Tree for the code as the user types. Git support, Opening files within app and custom terminal commands is in the prototype phase, and custom file save is already implemented. I have even devised a logic to implement a custom file browser, since the default flutter package is not supported in all platforms. All of these features are using just Dart and Flutter. No other programming language is used. The app is in private development for now, and it will be released to the public once all major features are implemented and tested.
Handling of the Tab character is the only important thing that I find to be missing right now. If there already is a way to implement this using TextInputFormatter
, that will be great. As far as I know, there isn't, but may be I haven't looked in the right place.
As of now, all I need is to control the display of the \t character. In theory, the TextInputFormatter
should be able to handle it, as it seems like it was made for purposes like this.
@TimWhiting
Is there anyway to implement this without the use of a predefined Formatter? Does the TextInputFormatter
support low-level customisation like that?
According to the TextInputFormatter
docs: A TextInputFormatter
can be optionally injected into an EditableText
to provide as-you-type validation and formatting of the text being edited.
So it can format / allow characters / disallow characters, alter text (replace \t with two / four spaces). But it is not meant for controlling how characters are displayed. As @gspencergoog mentioned, visual tab width for display should probably be a property on TextStyle
, but is not possible now. I suspect that will involve some engine work.
@TimWhiting
Oh ok then. Thanks for the helpful response. It seems like something like this won't be implemented in the flutter engine for a long time. So for now and the foreseeable future, Tab characters in the TextField in my application will look like half-spaces. That's really counterproductive. And unfortunate. At least, it will still be Tab characters when the user saves the file.
You might be able to create some sort of workaround for now without engine changes, but it will probably be more complex. I'm really not sure what is required to actually display tabs better, maybe the engine is not actually involved.
@TimWhiting
I had a brief look at: https://pub.dev/packages/flutter_multi_formatter
and its Github Repository: https://github.com/caseyryan/flutter_multi_formatter
But it seems to be a predefined static spacing between two characters and doesn't seem to be dynamic.
@AldrinMathew Yeah formatters aren't what you are looking for:
@gspencergoog I've implemented two approaches to the tab character / tab focus problem:
Approach 1: Escape to exit entering tabs into the textfield and move to next field. Shift escape to exit entering tabs and move to previous field Approach 2: Tabs aren't automatically captured when textfield becomes focused until user presses enter, escape exits the tab entering mode but still has focus on the textfield, as a part of the regular tab order. (There is an 'outer' and 'inner' hierarchical focus, that you navigate using enter / escape).
2 seems like the better approach and feels more natural since you can tab right past the field without automatically getting captured. Also probably fits best with voice/accessibility interfaces. The shift-escape-tab solution feels awkward, but tabbing to the previous field is probably less used.
Here is the code: https://github.com/TimWhiting/test_app
And the demo app on github pages: https://timwhiting.github.io/test_app/#/
@TimWhiting
I tested the Test App and the second implementation (Escape and Enter to exit and enter TabScopes) makes more sense. It is not much of hindrance to accessibility, and changes focus only when required and not automatically.
@TimWhiting
The current implementation in my code editor changes the focus every time the user presses Tab key and only refocuses on a second key press. Do I have the permission to use the implementation of Shortcuts & IndentationAction in your Test App in my application?
Yeah you have permission. It's meant to be a sample to help solve this issue and determine what the desired behavior is. There might be better ways of doing it. Hopefully something like it will be integrated into the framework someday.
Another conflicting use-case of Tab in text fields is for tab auto-complete. It seems to me that this can be distinguished from a insert of a literal tab by first checking if there is a suggestion available and the selection is empty, if so, then the first suggestion should be applied. If there is no suggestion available or the selection is not empty than the tab should be taken as a literal tab.
Any news about this topic?
@TimWhiting The design doc looks like it's on the right track to me, are you still working on bringing it to Flutter? Happy to help if needed.
@justinmc I was waiting for feedback on the design doc and for all of the changes around TextEditing / Shortcuts / Actions that were happening at the time, and since then I have had some other priorities. I'm busy with a bunch of stuff right now for my Master's Thesis, so would welcome any contribution or help you have to offer. If you want to fold these changes into your text editing refactor that would be great!
Sorry I thought I had already replied here. I will see if I can get this in as part of my current text editing work. Thanks for the great design doc and good luck on your thesis!
The triaged-desktop
label is irrelevant if there is no team-desktop
label or fyi-desktop
label.
Tab Character \t should be displayed as indentation in EditableText, TextField and all implementations of Text widgets in Desktop
This is a common behaviour in many desktop applications
Flutter Channel: master Platform: Desktop, Linux Version: 2.1.0-11.0.pre.138
When Tab key is pressed while the TextField is focused, in a Flutter Desktop Application, by default, the focused TextField is unfocused and the focus shifts to another widget. That is a problem in my case as I want the user to be able to enter tab characters. But I partially solved it by using a RawKeyboardListener to detect when the user presses Tab key, and then inserted a \t to the TextField at the current cursor position through its controller. The problem is that, the \t character is displayed as a small space, almost half as wide as whitespace, which is counterproductive. There should be an option to configure how \t is displayed, as it can be of multiple number of spaces' width, and it should be customisable.
I believe this is not exactly a bug. For mobile devices, the Tab key is irrelevant. For web, pressing Tab key is helpful in shifting focus between UI elements. But for desktop, it makes sense to have an option to customise how a Tab character is displayed in a TextField.
Suggestion
Add an option to disable focus shifting on Tab press on Desktop and add Tab character to the TextField. Provide a way to customise Tab character display, by equating it to a specific number of whitespaces that can be changed if required.