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

MultiLineTextInput widget persistently takes on rich formatting on a paste operation #2957

Open
kcoombs opened this issue Nov 16, 2024 · 6 comments
Labels
bug A crash or error in behavior. macOS The issue relates to Apple macOS support. windows The issue relates to Microsoft Windows support.

Comments

@kcoombs
Copy link

kcoombs commented Nov 16, 2024

Describe the bug

When pasting rich-formatted text into a MultiLineTextInput widget, the widget takes on the rich formatting.

Steps to reproduce

  1. Launch a Toga application that includes a MultiLineTextInput widget. e.g., from the Toga repository, examples/multilinetextinput.
  2. Copy rich-formatted text from another application, e.g., MS Word, TextEdit, a web browser.
  3. Paste into the MultiLineTextInput widget.
  4. Rich-formatting is preserved in the MultiLineTextInput widget. The formatting persists even when clearing the value (e.g., "clear" button in the Toga multilinetextinput example).

Expected behavior

While rich formatting may be desirable in some situations, I'd expect the default behavior to be displaying only plain text, like a TextInput widget.

Screenshots

Before paste:

Screenshot 2024-11-15 at 18 19 16

Rich text (TextEdit):

Screenshot 2024-11-15 at 18 21 04

After paste:

Screenshot 2024-11-15 at 18 21 22

After clear:

Screenshot 2024-11-15 at 18 21 29

Environment

  • Operating System:

    • MacOS Sequoia 15.1
    • Windows 11
    • Others???
  • Python version:

    • 3.12.7
  • Software versions:

    • Toga: 0.4.8

Logs


Additional context

No response

@kcoombs kcoombs added the bug A crash or error in behavior. label Nov 16, 2024
@freakboy3742
Copy link
Member

Confirming this definitely isn't the intended behavior. I'm guessing we've missed an option when configuring the native text widgets.

Not sure if this also affects GTK, iOS or Android; seems highly plausible it might be an issue on GTK.

@kcoombs
Copy link
Author

kcoombs commented Nov 16, 2024

As least so far as MacOS goes, this seems to prevent MultiLineTextInput from taking rich-formatted text on a paste:

diff --git a/cocoa/src/toga_cocoa/widgets/multilinetextinput.py b/cocoa/src/toga_cocoa/widgets/multilinetextinput.py
index c651fa8e4..e908ecb6d 100644
--- a/cocoa/src/toga_cocoa/widgets/multilinetextinput.py
+++ b/cocoa/src/toga_cocoa/widgets/multilinetextinput.py
@@ -36,6 +36,7 @@ class MultilineTextInput(Widget):
 
         # Create the actual text widget
         self.native_text = TogaTextView.alloc().init()
+        self.native_text.setRichText_(False)
         self.native_text.interface = self.interface
         self.native_text.delegate = self.native_text

See https://developer.apple.com/documentation/appkit/nstextview/1449538-richtext.

@kcoombs
Copy link
Author

kcoombs commented Nov 16, 2024

For Windows, it doesn't seem like you can disable rich text in the Winforms RichTextBox entirely, but intercepting and handling a CTRL-V to only take the plain text seems to work:

diff --git a/winforms/src/toga_winforms/widgets/multilinetextinput.py b/winforms/src/toga_winforms/widgets/multilinetextinput.py
index 7111d47c1..30667dc82 100644
--- a/winforms/src/toga_winforms/widgets/multilinetextinput.py
+++ b/winforms/src/toga_winforms/widgets/multilinetextinput.py
@@ -22,11 +22,20 @@ class MultilineTextInput(TextInput):
         self.native.GotFocus += WeakrefCallable(self.winforms_got_focus)
         self.native.LostFocus += WeakrefCallable(self.winforms_lost_focus)

+        # Handle paste (CTRL+V) events
+        self.native.KeyDown += self.handle_paste
+
         # Dummy values used during initialization
         self._placeholder = ""
         self._placeholder_visible = True
         self.set_color(None)

+    def handle_paste(self, sender, event):
+        if event.Control and event.KeyCode == WinForms.Keys.V:
+            event.SuppressKeyPress = True
+            if WinForms.Clipboard.ContainsText():
+                self.native.SelectedText = WinForms.Clipboard.GetText(WinForms.TextDataFormat.Text)
+
     def winforms_got_focus(self, sender, event):
         # If the placeholder is visible when we gain focus, the widget is empty;
         # so make the native text empty and hide the placeholder.

This isn't as general as the MacOS solution in my prior comment because the box still takes rich text, and this only handles placing rich text into the box via CTRL-V. Still, a MultiLineTextInput widget doesn't appear to accept drag-and-drop on Windows, so this may be sufficient.

Another case to consider may be if a user provides a UI-based paste option (e.g., Edit > Paste), so perhaps there is another paste event that would need to be intercepted to cover that.

@kcoombs
Copy link
Author

kcoombs commented Nov 16, 2024

In my quick testing, this does not appear to be an issue for GTK.

It also does not appear to be an issue for iOS and Android—at least when pasting from macOS into an emulator, I haven't tested it natively.

@freakboy3742 freakboy3742 added macOS The issue relates to Apple macOS support. windows The issue relates to Microsoft Windows support. labels Nov 17, 2024
@freakboy3742
Copy link
Member

This isn't as general as the MacOS solution in my prior comment because the box still takes rich text, and this only handles placing rich text into the box via CTRL-V. Still, a MultiLineTextInput widget doesn't appear to accept drag-and-drop on Windows, so this may be sufficient.

Looking at the implementation - the underlying widget is a RichTextBox, which is likely why there aren't any options to disable rich text.

I did find this answer on StackOverflow which suggests a possible method for configuring a RichTextBox by poking the underlying win32 API to disable some mode settings on the widget. If you want to tinker with this approach, TextInput has an existing usage of SendMessage to trigger some internal logic around placeholders.

Another case to consider may be if a user provides a UI-based paste option (e.g., Edit > Paste), so perhaps there is another paste event that would need to be intercepted to cover that.

At least at present, we haven't got a default paste menu item for Windows (although perhaps we should); so this isn't an immediate issue; but agreed that a "generic" solution not directly tied to the keyboard handler would be preferable.

@mhsmith
Copy link
Member

mhsmith commented Nov 18, 2024

Every text box on Windows has a right-click context menu with a Paste command, which is affected by this issue as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A crash or error in behavior. macOS The issue relates to Apple macOS support. windows The issue relates to Microsoft Windows support.
Projects
None yet
Development

No branches or pull requests

3 participants