Clickable textbox

Started by billarhos, 19 December 2018, 19:44:34

billarhos

Hi.
Using a textbox widget to display some info text, i came in front of two obstacles.

1.Even using "setReadOnly" function, in "editbox" you can still select some words or lines.
2.I was unable to find a way to catch a mouse left click on "editbox", in order to close my help form.

I am using 0.7.5 version.

thanks for reading

texus

Nr 1 is by design, read-only just means you can't change the text but shouldn't prevent the user from still being able to copy the text. One thing you could do is disable the widget. It won't respond to any events after that though. Another option is to use a label, they can be given a size and have text fit inside them with word-wrap as well. Labels don't support a background texture or scrollbars though.

I don't understand what your use case is for nr 2. Could you elaborate on what you are trying to do exactly?

billarhos

1. I forced to use textbox exactly because it has scrollbars. Sometimes text is more than a page.
2. Imagine you have a textbox filling the whole area. When this textbox appears it is easier for the user, and even more easier when this app running in kiosk machines
with touchscreen monitors, to touch (left click simulation) somewhere inside this textbox when he/she wants to close this form with the textbox.
The text usually contains help info.

Basically, the first one it is not such a problem.

I managed partially do that overriding "global mouse enter" but then it is completely useless in normal pc machines.


texus

1.
If you were using TGUI 0.8 then I would have suggested putting the label in a ScrollablePanel.
You could draw a Panel, put the label inside it and also put a scrollbar inside the panel. Then just change the position of the label when the scrollbar is moved. I just looked at the 0.7 source code and it seems like Panel didn't support padding yet, so the result won't be good if you want to have a bit of padding at the top or bottom of your panel, but it should work otherwise.

2.
One workaround that I can think of would be to listen to the MouseEntered and MouseLeft events of the TextBox to know if the mouse is on top of it and then in your event loop when you get a mouse down event you could close the form if the mouse was on top of the textbox. But since you mentioned kiosk machines, I'm not certain the MouseEntered and MouseLeft will work properly when using a touchscreen instead of a mouse. It isn't really an easy workaround either.

What exactly is the "form" you are talking about? Is it something from TGUI like a panel or child window? Listening to the unfocused event from that form might be an option, but if focusing widgets is as broken in 0.7 as I've always claimed it was then that probably won't work properly either.


What about listening to the "focused" event of the TextBox, instead of trying to close the form on a mouse press?

billarhos

Done with sf::Events

if (event.type == sf::Event::MouseButtonPressed

For the record, touch screen in kiosks just behave as mouses. The default settings have mouse emulation, that normal is left click down and up. However you can change that
with right click down and up.

texus

Even if it didn't emulate a mouse, TGUI supports touch events (as long as SFML supports them on that platform). What I was uncertain about was whether mouse move events would be send when using a touch screen, because MouseEntered and MouseLeft depend on mouse move events and may thus not work correctly on a touch screen.

Is there a reason why you rely on mouse pressed instead of using the focused event of the text box? A mouse down event on a TextBox should always trigger the focused callback. If the focused event somehow doesn't cover your use case then it might still be a good idea to add mouse event callbacks to the TextBox.

billarhos

I am working with touch monitors (like ELO https://www.elotouch.com/ ) since 2000.

I do not think that i can miss a press event. If i miss a press event then something is not working correct. After all, a press event is a pre-event than focus event, so i am a bit faster. LOL

Right now the help screen closes without any problem by touching/clicking on any point in "editbox".

There is no need to implement something in 0.7.5 right now. However in the 0.8, i think that adding some features in widgets, like disabling select text without disabling the whole "textbox" widget or adding some extra callbacks is a plus, in this 'almost' (lol) perfect library.

After you added the "treeview" widget, i have one more motivation to start using the newer version.

thank you Texus

texus

QuoteHowever in the 0.8, i think that adding some features in widgets, like disabling select text without disabling the whole "textbox" widget or adding some extra callbacks is a plus
If I understand the use case for it then I'll add it, but I'm still not convinced that there is a reason to add these "features".
- You want text that can be scrolled. The only perfect way would be if Label supported scrollbars, but since that isn't possible you would have to use a workaround (unless I add support for scrollable labels, which might be a nice thing to have in the future). To me, using a TextBox and disabling the interaction with the text inside it feels like a worse workaround than to just creating a Label inside a ScrollablePanel. In 0.7 the workaround with the TextBox makes sense because ScrollablePanel didn't exist, but if we are looking at improving 0.8 for future users then it doesn't seem necessary.
- If both mouse press callback and focused callback work equally well then I don't need to implement them both. Both events are triggered in the same frame and for the same reason, so I can't come up with a scenario where you would need to do something on mouse press that you wouldn't be able to do on the focus event.

QuoteAfter all, a press event is a pre-event than focus event, so i am a bit faster. LOL
If you intercept the event before passing it to TGUI then you will always be faster, but a widget actually receives the focus BEFORE it is told that the mouse went down on it, so from the widget point of view the focus event is a pre-event to the mouse press event :)

billarhos

Yes, i agree with you, if you must go with "label" and "scrollbars" then go (for 0.8). In my case, i would never used "textbox" in first place if i had a "label" with "scrollbars". I never wanted to write something (aka textbox). Yes, forget everything about i said for the textbox.

But on the other hand the label must have a click event (has it?). In future, maybe me or someone else will face the same experience when he would try to catch a click on a label. In my mind, focus events does not "connect" with click events. And in the physical point of view, we have a touch/click event. The focus event is an after-effect. Yes, i understood that it happening before the actual click event. And on the other hand, in my mind, when i make visible a widget (or adding it, into the container) it tells me that gain instantly focus as long is the top most widget, but obviously not.

As i said, right now you don't have to do something. I have already implemented what i wanted.

I am sure that this kind of discussing make things better.




texus

Label does have a click event (it inherits from ClickableWidget), as it is the only way to "interact" with the widget. The text box on the other hand was designed for inputting text and not for acting on things like being clicked on.

I was already wondering what I could work on next now that the TreeView is finished, so I'm going to try and give label an optional vertical scrollbar in TGUI 0.8.3.
I wonder though, if I have a Label with a scrollbar, should it send a click event when the click happens on the scrollbar? For your use case it should, but widgets typically don't send events when their scrollbar is dragged.

In my mind you don't want to close the form when clicking on the text box, you want to close the form when the user stops interacting with it, i.e. when unfocusing it. I didn't come up with the focus event until pretty late myself, I came up with all the other workarounds first before I realized that the focus event was an option. So I definitely get your point about the click event being more intuitive than the focus.
Actually I just notice a similarity with code I wrote before. When I open a dialog (panel widget) in front of everything else then I just put a panel with a semi-transparent black background between the original widgets and the dialog. Due to the semi-transparency it clearly shows the user that he has to interact with the dialog but I also used the click event on the panel to cancel the dialog.

Discussions like this can definitely make things better. I can be a bit stubborn and not want to change things sometimes, but I usually do give it a lot of thought even after the discussion ends. In the end it is very educational for me to know what difficulties people find when trying to use TGUI. If it wasn't for this discussion then the scrollable label wouldn't be on the planning anywhere soon.

billarhos

Great news. A plus for me to use the newer version. In fact, i am planning to go for it, as soon as the visual studio 2019 for community pop up. I am stuck with 2015 for so long...

The thing that made me want this click callback is that i wanted a full screen text-info-help widget. And the only way to close this info-screen is to click on it when you finish reading. Kiosk machines normally can have a few physical buttons but sometimes there are no buttons. The other devices you can see on those machines are note and coin acceptors, money hopper, pos printer, card reader, scanner and camera.

Click on scroll bars has nothing to do with what i want. The area on scroll bar is to scroll the text. In my case i want a click on label's clean area.
Or, we can have both callbacks, one for scrollbar and one for text area. But, i can not think where it can be useful in the case of scrollbar.

And yes the example with dialog you mention, is pretty much like my case.





texus

With your last post I finally got the correct view on what you are doing. I completely misinterpreted where the text box was located. I was imagining having a full screen textbox and then another window on top of it and that you wanted to close that window when the text box (which is partially hidden by the window) was clicked. I didn't realize that the text box was part of the form that you wanted to close. That is why I came up with the focus event, because you switch focus from the window to the text box behind it. But obviously the focus event wouldn't work if the text box was on the form itself as it already has focus.
Looking back at it, the situation that I was imagining was silly but there was almost nothing in your second post that indicated that the scenario in my head was wrong. The words "close this form with the textbox" do indicate that the text box is in the panel, but I interpreted that part of the sentence as "closing the form by clicking on the textbox", which no longer indicates that the text box has to be on top of the panel. Although the misinterpretation is my fault, it could help to be more verbose about how your forms look next time, perhaps even include a few screenshots. The more details you provide, the less chance there is that I misinterpret it.

I've already finished with adding a scrollbar to the Label class (I just have to decide whether I enable them by default if the text no longer fits or whether I disable them by default for 100% backward compatibility). Now I got to find something else to do :)
I guess I could try writing a multi-column list box again, but the last time two times I tried writing it I ended up playing games the entire week instead of programming :)

billarhos

Ok then. I am happy that at the end everybody understood. In future, i 'll keep in mind to add screen-shots.

The best option for label's scrollbar, if it should be enable or disable is to add an 'enum' Scrollbar State = {enabled, disabled, auto} along with a 'setter' and a 'getter' functions but maybe that requires a lot of work. In this way you can catch all future requests.
By default, it should be disabled and if someone uses long text then he should enable scrollbar at the beginning.

While having this conversation i always hesitated to ask you to go for the multi-column list box. Is a 'must' widget. And after the 'treeview' widget you added, there are no more big work to be done. And i really need it because i wand to rewrite an olf dj-music program i made (dot net, 10 years ago)
And after that, i will have no excuse of using the latest version of 'tgui'.


texus

QuoteThe best option for label's scrollbar, if it should be enable or disable is to add an 'enum' Scrollbar State = {enabled, disabled, auto} along with a 'setter' and a 'getter' functions
It already exists, both ScrollablePanel and Label contain a ScrollbarPolicy which describes when the scrollbar shows up:
Code (cpp) Select
enum class ScrollbarPolicy { Automatic, Always, Never };

QuoteBy default, it should be disabled and if someone uses long text then he should enable scrollbar at the beginning.
That is probably the best option and I was planning to do it this way. Although even on Automatic the scrollbar wouldn't show up until someone would use a long text. There are very few cases where a scrollbar would suddenly pop up unexpectedly when using Automatic by default, but these cases still exist so using Never as default is the safest option. In 0.9 (if the version will ever exist) I'll switch to Automatic as default though as I won't have to worry about compatibility then.

I'll look into the multi-column listbox again. I'm not sure whether I should go for a simplified port of the windows ListView control (with only supporting the "report view" at first) or whether I should just create a MultiColumnListBox class though. I started with one of the two last time but I deleted the files and decided to choose the other, but I have absolutely no idea which option I picked last time :)

billarhos

QuoteI'm not sure whether I should go for a simplified port of the windows ListView control (with only supporting the "report view" at first) or whether I should just create a MultiColumnListBox class though
Can not say. But the report view is the most wanted. Also keep in mind that dot net list box has a BeginUpdate() method, that prevents the control from drawing until the EndUpdate() method is called. In this way when you can add items in listview very rapidly.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.listview.beginupdate?view=netframework-4.7.2

texus

I'm not going to do that, if all goes well then it should be really fast without having to do something like a BeginUpdate/EndUpdate. I use the ListView regularly at work (in c++) and I'm always annoyed by how slow it is when adding data.
With SFML you control when things are drawn anyway so you don't have to "prevent drawing" during the update.

Adding several hundreds to a few thousands of lines is so slow that it feels like the list view is just badly optimized. But I guess it has to do with the way it is designed too. Yesterday I started writing the header file and I intended to keep a similar way of adding items as in the windows component, i.e. by having an Item struct containing the caption and subitems. While doing so I realized that although this would be easy for the user, it meant that the user could change an item without the widget knowing about it and the widget would have to update its internal list of items every frame. By not allowing direct access to the Item struct and providing functions like addSubItem and changeItem, the widget can keep full control of when an item changes and I can reduce the amount of work that has to be done every frame.

You can expect the same performance in the ListView than you get now in the ListBox. And I don't mean the 1.7 seconds to add 10000 items like in TGUI 0.7, I mean the 0.083 seconds that it takes in 0.8.