fyne-io / fyne

Cross platform GUI toolkit in Go inspired by Material Design
https://fyne.io/
Other
25.25k stars 1.4k forks source link

Add a read-only mode to Entry #5263

Closed pjanx closed 2 weeks ago

pjanx commented 2 weeks ago

Checklist

Is your feature request related to a problem?

Entry is Fyne's only way of presenting selectable text to the user. The user may not want to change the text on accident.

Is it possible to construct a solution with the existing API?

The best I can come up with is to SetText back to the original value in an OnChanged callback, however this is only an approximation of the desired behaviour (defect: select text → press a rune key → cursor jumps elsewhere).

type roEntry struct {
    widget.Entry
}

func newRoEntry() *roEntry {
    e := &roEntry{}
    // Or whatever...
    e.MultiLine = true
    e.Wrapping = fyne.TextWrapWord
    e.ExtendBaseWidget(e)
    return e
}

func (e *roEntry) SetText(text string) {
    e.OnChanged = nil
    e.Entry.SetText(text)
    e.OnChanged = func(string) { e.Entry.SetText(text) }
}

func (e *roEntry) AcceptsTab() bool {
    return false
}

Describe the solution you'd like to see.

The Entry works as usual, but may only be modified programmatically, and not through, e.g., typing, or clipboard actions.

type Entry struct {
    ...
    Readonly bool
    ...
}
dweymouth commented 2 weeks ago

entry.Disable() is what you're looking for

pjanx commented 2 weeks ago

That is not at all the same thing, and should not be.

A read-only widget supports selecting text with the keyboard. A disabled widget rejects events.

Another problem with disabled Entries is that they're completely unreadable.

andydotxyz commented 1 week ago

A read-only widget supports selecting text with the keyboard. A disabled widget rejects events.

This is not accurate - the text of a disabled entry can be selected and copied.

If your issue is with the disabled theme then open an issue for that so we can resolve it.

pjanx commented 1 week ago

I was talking about how toolkits behave normally (from memory Win32's ES_READONLY, GTK's editable), i.e., expectations. Admittedly, a read-only web browser <input> doesn't allow keyboard selection either, but it also doesn't change colour.

In that context, Fyne's current Entry in its disabled state is neither disabled (it can change state through user action) nor read-only (it is certainly not readable, and you cannot use the keyboard to move the cursor around or scroll).

andydotxyz commented 1 week ago

This issue has been closed as noted above. The original request:

The user may not want to change the text on accident.

Is provided by not using an Entry, or by making the entry Disabled. For text that should not change use Label, for text that could change but it is not allowed just now use Entry.Disable().

The rest if your comment is becoming a semantic discussion unfortunately so I will do my best to unpick misunderstanding or definition mismatch.


Admittedly, a read-only web browser

A web browser is not an editable component for a user. If you must compare this to an HTML context please think about input fields only.

Fyne's current Entry in its disabled state is neither disabled (it can change state through user action)

Excuse me? I think this is a misunderstanding of "state". A disabled entry cannot change its content through user action. It can however change a) selection, b) size, c) position - none of which I would consider the "state of the entry" - it is disabled to avoid "changing the text on accident" as you noted in the initial issue.

it is certainly not readable, and you cannot use the keyboard to move the cursor around or scroll

I come back to the concern that you are thinking from a developer perspective ("other toolkits do this") and not from a user point of view (an input that /looks/ writeable but is actually read-only is confusing because there is no hint that the input capability has changed.

This reply is not to open a discussion, it is to explain why a read-only Entry will not be added, either use Disabled (to show that this entry is not currently editable) or use a Label or similar (to show that the text is read only). There are clear semantics to both and they are conveyed to the user through important visual cues.

pjanx commented 1 week ago

Admittedly, a read-only web browser

A web browser is not an editable component for a user.

GitHub Markdown's rendering ate my text, before I edited it, which was a read-only web browser <input>.


The arguments for a separate state indeed are about "being disabled" differing semantically from "not being editable".

It can however change a) selection

This is the state, in a stricter view. It will invoke the OnCursorChanged callback.

It is readable on most screens

image

This clearly fails all accessibility requirements, even on, or especially on a calibrated display (some devices have a terrible gamma curve, so YMMV). I recognise this would be for a separate issue, yet it supports the argument, in that even Fyne considers a non-editable state different from a disabled (unusable) one.

Scroll keyboard events should work, they are not editing the content of the scroll

A disabled entry /is/ selectable

Disabled Fyne Entries currently do not receive keyboard focus*, or at minimum Page Down/Up does not work, and they should not receive it. A read-only Entry would.

When using the keyboard, you observably select from the cursor, and the widget must be focusable.

A cursor indicates that input can be made

In Fyne's world view, maybe. But this is an invalid assumption in general. You're very mouse/touch-centric.

I come back to the concern that you are thinking from a developer perspective [...] and not from a user point of view [...]

The use case is: Tab to an entry with a lot of text, scroll through it using the keyboard, possibly select text using the keyboard as well, and maybe copy it to the clipboard. This is not possible with a Disabled Entry, and it still isn't possible if you recolour the text to be actually readable.

The only way to achieve a meaningful result thus far is with my workaround of resetting the text back.


* Example where keyboard events can be observed:

package main

import (
    "strings"

    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/widget"
)

func main() {
    a := app.New()
    w := a.NewWindow("Bugs")
    me := widget.NewMultiLineEntry()
    me.Wrapping = fyne.TextWrapWord
    me.SetText(strings.Repeat("Lorem ipsum dolor sit amet\n", 100))
    me.Disable()
    w.SetContent(me)
    w.ShowAndRun()
}
andydotxyz commented 1 week ago

Admittedly, a read-only web browser

A web browser is not an editable component for a user.

GitHub Markdown's rendering ate my text, before I edited it, which was a read-only web browser <input>.

Ah that makes more sense. From w3schools "A read-only input field cannot be modified (however, a user can tab to it, highlight it, and copy the text from it)." This description matches a Fyne disabled Entry with the added benefit that it is clear to the user that it cannot be edited.

All other input fields indicate disabled state by being greyed out and there have been no requests for a read-only mode on any others.

image

This clearly fails all accessibility requirements, even on, or especially on a calibrated display (some devices have a terrible gamma curve, so YMMV). I recognise this would be for a separate issue, yet it supports the argument.

Then open a ticket about the colours of the default theme. A bug in the theme is never a reason to add more APIs.

Disabled Fyne Entries currently do not receive keyboard focus*, or at minimum Page Down/Up does not work, and they should not receive it.

Feel free to open a bug to get that resolved if it really doesn't work.

The use case is: Tab to an entry with a lot of text, scroll through it using the keyboard, possibly select text using the keyboard as well, and maybe copy it to the clipboard. This is not possible with a Disabled Entry.

Ah, so you have found a bug where keyboard controls do not match the touch features. Please do open a bug and we can tag it appropriately.