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

SelectionArea fails for TextSpan elements #3035

Closed
sgrefen opened this issue Apr 16, 2024 · 3 comments · Fixed by #3066
Closed

SelectionArea fails for TextSpan elements #3035

sgrefen opened this issue Apr 16, 2024 · 3 comments · Fixed by #3066
Labels
bug Something isn't working

Comments

@sgrefen
Copy link
Contributor

sgrefen commented Apr 16, 2024

Description
When ft.Text is in a SelectionArea the on_change callback works as intended, unless either selectable is True or the Text is using TextSpans. In the later case the spans are not selectable (unless selectable is True which breaks the on_change callback).
WebView and local Linux client behave identically.

Code example to reproduce the issue:

import flet as ft

name = "CupertinoSegmentedButton example"


def example(tag="plain",s=False):
    def pev(e):
        try:
            print("PEV(%s %s)"%(tag,s),vars(e.data))
        except Exception as ex:
            print(ex)
            print(e)

    def pe(e):
        try:
            print("PE(%s %s)"%(tag,s),vars(e))
        except Exception as ex:
            print(ex)
            pev(e)



    return ft.SelectionArea(
                  content=ft.Text(value="TEST [ %s select %s]\n 43240932840329\nsffsf"%(tag,s),
                  spans=[ ft.TextSpan("Test\n"), ft.TextSpan("sjflfff\n"), ft.TextSpan("sfsfdfd\n"), ft.TextSpan("sdfsdfsd\n")] if tag != "plain" else None,
                  selectable=s,
                  ),on_change=pe
    )


def main(page: ft.Page):
    page.add(example())
    page.add(example("spans"))
    page.add(example(s=True))
    page.add(example("spans",True))


#ft.app(target=main,view=ft.AppView.WEB_BROWSER)
ft.app(target=main)

Describe the results you received:

Only the first text works as expected, this are selectable areas
image
and only these callbacks are generated:
$ python tcg.py package:media_kit_libs_linux registered. PE(plain False) {'target': '_2', 'name': 'change', 'data': '', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'T', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TE', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TEST [ plain select False]\n 432', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TEST [ plain select False]\n 4324', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': 'TEST [ plain select False]\n 43240932840329\nsffsf', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')} PE(plain False) {'target': '_2', 'name': 'change', 'data': '', 'control': SelectionArea(), 'page': Page(id='page', route='/', pwa='false', web='false', debug='false', platform='linux', platformbrightness='light', media='{"padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_padding":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0},"view_insets":{"top":0.0,"right":0.0,"bottom":0.0,"left":0.0}}', width='1280.0', height='720.0', windowwidth='1280.0', windowheight='720.0', windowtop='0.0', windowleft='0.0', clientip='', clientuseragent='', windowminimized='false', windowmaximized='false', windowfocused='false', windowfullscreen='false')}

Describe the results you expected:

Expectation is receiving events also for text-spans, ideally as array with text_span-id + selected text in span

Additional information you deem important (e.g. issue happens only occasionally):

Flet version (pip show flet):

Name: flet
Version: 0.22.0
Summary: Flet for Python - easily build interactive multi-platform apps in Python
Home-page: 
Author: Appveyor Systems Inc.
Author-email: hello@flet.dev
License: Apache-2.0
Location: /home/grefen/.local/lib/python3.12/site-packages
Requires: cookiecutter, fastapi, flet-runtime, packaging, qrcode, uvicorn, watchdog
Required-by: 
``


**Operating system**:

<!--
Linux
-->

**Additional environment details:**
@sgrefen
Copy link
Contributor Author

sgrefen commented Apr 17, 2024

One hint is in flutter/flutter#113530 , in the thread the recommendation is to use Text.rich instead of RichText.
Text.dart:

return control.attrBool("selectable", false)!
          ? (spans.isNotEmpty)
              ? SelectableText.rich(
                  TextSpan(text: text, style: style, children: spans),
                  maxLines: maxLines,
                  textAlign: textAlign,
                )
              : SelectableText(
                  text,
                  semanticsLabel: semanticsLabel,
                  maxLines: maxLines,
                  style: style,
                  textAlign: textAlign,
                )
          : (spans.isNotEmpty)
              ? RichText(
                  text: TextSpan(text: text, style: style, children: spans),
                  maxLines: maxLines,
                  softWrap: !noWrap,
                  textAlign: textAlign,
                  overflow: overflow,
                )
              : Text(
                  text,
                  semanticsLabel: semanticsLabel,
                  maxLines: maxLines,
                  softWrap: !noWrap,
                  style: style,
                  textAlign: textAlign,
                  overflow: overflow,
                );

I'm going to try a build with the change

@sgrefen
Copy link
Contributor Author

sgrefen commented Apr 17, 2024

The following patch seems to fix it:

git diff -u ../packages/flet/lib/src/controls/text.dart
diff --git a/packages/flet/lib/src/controls/text.dart b/packages/flet/lib/src/controls/text.dart
index 7d489e5..54d8217 100644
--- a/packages/flet/lib/src/controls/text.dart
+++ b/packages/flet/lib/src/controls/text.dart
@@ -116,8 +116,9 @@ class TextControl extends StatelessWidget with FletStoreMixin {
                   textAlign: textAlign,
                 )
           : (spans.isNotEmpty)
-              ? RichText(
-                  text: TextSpan(text: text, style: style, children: spans),
+              ? Text.rich(
+                  TextSpan(text: text, style: style, children: spans),
+                  semanticsLabel: semanticsLabel,
                   maxLines: maxLines,
                   softWrap: !noWrap,
                   textAlign: textAlign,

@ndonkoHenri
Copy link
Collaborator

Will you mind opening a PR with the suggestion?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants