TextBox easy control (rapid text editing)

Started by Myster, 19 August 2015, 09:09:36

texus

#15
That PageDown issue wasn't very hard, the case where there are less lines than fill in the text box was just not checked.
I did find another rare crash with PageDown when there was a lot of text though, one that was much harder to reproduce, but I managed to fix it eventually. I just hope there aren't any other bugs like that one left.

Code (cpp) Select
            case sf::Keyboard::PageDown:
            {
                // Move to the bottom line when not there already
                if (m_topLine + m_visibleLines > m_lines.size())
                    m_selEnd.y = m_lines.size() - 1;
                else if (m_selEnd.y != m_topLine + m_visibleLines - 1)
                    m_selEnd.y = m_topLine + m_visibleLines - 1;
                else
                {
                    // Scroll down when we already where at the bottom line
                    Padding padding = getRenderer()->getScaledPadding();
                    auto visibleLines = static_cast<std::size_t>((getSize().y - padding.top - padding.bottom) / m_lineHeight);
                    if (m_selEnd.y + visibleLines >= m_lines.size() + 2)
                        m_selEnd.y = m_lines.size() - 1;
                    else
                        m_selEnd.y = m_selEnd.y + visibleLines - 2;
                }

                if (!m_lines[m_selEnd.y].isEmpty() && (m_lines[m_selEnd.y][m_lines[m_selEnd.y].getSize()-1] == '\n'))
                    m_selEnd.x = m_lines[m_selEnd.y].getSize() - 1;
                else
                    m_selEnd.x = m_lines[m_selEnd.y].getSize();

                if (!event.shift)
                    m_selStart = m_selEnd;

                updateSelectionTexts();
                break;
            }

Myster

Yes. It works good now)

Now I tried to make a selection the word by double clicking, based on your LeftKey and RightKey events (because I really better to select words that exceed the length of the line). But to be honest, I confused them.
There is a problem: if the caret is at the beginning of the word, it captures the word on the left too. If the cursor at the beginning of the line (i.e. when x = 0), it selects all the text before (from {0, 0} to word). And with the right button is nearly the same, but to the opposite side (to {0, linesize}).
To select a word by double-clicking "skippedWhitespace" bother me enough. :o Maybe it doesn't need to do this?
There is almost nothing has changed, except for an additional variable m_selClicked, and changes in the first part to m_selStart

Code (cpp) Select
            // Check if this is a double click
            if ((m_possibleDoubleClick) && (m_selStart == m_selEnd) && (caretPosition == m_selEnd))
            {
                // The next click is going to be a normal one again
                m_possibleDoubleClick = false;
               
                if( m_lines[m_selStart.y][m_selStart.x] == ' ' )
                {
                    // Select the space
                    m_selEnd.x = m_selStart.x + 1;
                }
                else
                {
                    // Select the word
                    sf::Vector2<std::size_t> m_selClicked = m_selStart;
                   
                    // Move to the beginning of the word
                    bool skippedWhitespace = false;
                    bool done = false;
                    for (unsigned int j = m_selClicked.y + 1; j > 0; --j)
                    {
                        for (unsigned int i = m_selClicked.x; i > 0; --i)
                        {
                            if (skippedWhitespace)
                            {
                                if (isWhitespace(m_lines[m_selStart.y][i-1]))
                                {
                                    m_selStart.x = i;
                                    done = true;
                                    break;
                                }
                            }
                            else
                            {
                                if (!isWhitespace(m_lines[m_selStart.y][i-1]))
                                    skippedWhitespace = true;
                            }
                        }

                        if (!done)
                        {
                            if (m_selStart.y > 0)
                            {
                                m_selStart.y--;
                                if (!m_lines[m_selStart.y].isEmpty() && m_lines[m_selStart.y][m_lines[m_selStart.y].getSize()-1] == '\n')
                                {
                                    if (!skippedWhitespace)
                                        m_selStart.x = m_lines[m_selStart.y].getSize()-1;
                                    else
                                    {
                                        m_selStart.x = 0;
                                        m_selStart.y++;
                                        break;
                                    }
                                }
                                else
                                    m_selStart.x = m_lines[m_selStart.y].getSize();
                            }
                            else
                            {
                                m_selStart.x = 0;
                                m_selStart.y = 0;
                            }
                        }
                        else
                            break;
                    }
                   
                    // Move to the end of the word
                    skippedWhitespace = false;
                    done = false;
                    for (unsigned int j = m_selClicked.y; j < m_lines.size(); ++j)
                    {
                        for (unsigned int i = m_selClicked.x; i < m_lines[m_selEnd.y].getSize(); ++i)
                        {
                            if (skippedWhitespace)
                            {
                                if (isWhitespace(m_lines[m_selEnd.y][i]))
                                {
                                    m_selEnd.x = i;
                                    done = true;
                                    break;
                                }
                            }
                            else
                            {
                                if (!isWhitespace(m_lines[m_selEnd.y][i]))
                                    skippedWhitespace = true;
                            }
                        }

                        if (!done)
                        {
                            if (!skippedWhitespace)
                            {
                                if (m_selEnd.y+1 < m_lines.size())
                                {
                                    m_selEnd.y++;
                                    m_selEnd.x = 0;
                                }
                            }
                            else
                            {
                                if (!m_lines[m_selEnd.y].isEmpty() && (m_lines[m_selEnd.y][m_lines[m_selEnd.y].getSize()-1] == '\n'))
                                    m_selEnd.x = m_lines[m_selEnd.y].getSize() - 1;
                                else
                                    m_selEnd.x = m_lines[m_selEnd.y].getSize();
                            }
                        }
                        else
                            break;
                    }
                }
            }...

Myster

Ignore my last post please. I rewrote double-click from scratch. But some things have coincided with your code. Although the double-clicking algorithm really was a bit different than Keys' events. And I really didn't use "skippedWhitespace" (it seems superfluous for that event).

There is little bug (if it acknowledges as a bug, it doesn't cause the crash :D ) - when selects the '\n' at the end of line (at the end of the paragraph especially), it selects word on next line or itself '\n' at the current (but visually the caret moves to beginning of the line)

I'll try to find time to finish, so that it will be selected left word or left space, but not the '\n'

But for now this result:

Code (cpp) Select
...
            // Check if this is a double click
            if ((m_possibleDoubleClick) && (m_selStart == m_selEnd) && (caretPosition == m_selEnd))
            {
                // The next click is going to be a normal one again
                m_possibleDoubleClick = false;
               
                if (isWhitespace(m_lines[m_selStart.y][m_selStart.x]))
                {
                    // Select the space
                    m_selEnd.x = m_selStart.x + 1;
                }
                else
                {
                    // Move start pointer to the beginning of the word
                    bool done = false;
                    for (unsigned int j = m_selStart.y + 1; j > 0; --j)
                    {
                        for (unsigned int i = m_selStart.x; i > 0; --i)
                        {
                            if (isWhitespace(m_lines[m_selStart.y][i-1]))
                            {
                                m_selStart.x = i;
                                done = true;
                                break;
                            }
                            else
                                m_selStart.x = 0;
                        }
                       
                        if (!done)
                        {
                            if (m_selStart.x == 0)
                            {
                                if (m_selStart.y > 0)
                                {
                                    m_selStart.y--;
                                    m_selStart.x = m_lines[m_selStart.y].getSize();
                                }
                                else
                                {
                                    done = true;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (m_selStart.x == m_lines[m_selStart.y].getSize())
                            {
                                m_selStart.y++;
                                m_selStart.x = 0;
                            }
                            break;
                        }
                    }
                   
                    // Move start pointer to the end of the word
                    done = false;
                    for (unsigned int j = m_selEnd.y; j < m_lines.size(); ++j)
                    {
                        for (unsigned int i = m_selEnd.x; i < m_lines[m_selEnd.y].getSize(); ++i)
                        {
                            if (isWhitespace(m_lines[m_selEnd.y][i]))
                            {
                                m_selEnd.x = i;
                                done = true;
                                break;
                            }
                            else
                                m_selEnd.x = m_lines[m_selEnd.y].getSize();
                        }
                       
                        if (!done)
                        {
                            if (m_selEnd.x == m_lines[m_selEnd.y].getSize())
                            {
                                if ((m_selEnd.y + 1) < m_lines.size())
                                {
                                    m_selEnd.y++;
                                    m_selEnd.x = 0;
                                }
                                else
                                {
                                    done = true;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (m_selEnd.x == m_lines[m_selEnd.y].getSize())
                            {
                                m_selEnd.y--;
                                m_selEnd.x = m_lines[m_selEnd.y].getSize();
                            }
                            break;
                        }
                    }
                }
            }
            else // No double clicking
...

Myster

Now all bugs were terminated. I added a few lines before the scan starting.

Code (cpp) Select
                ...
                // The next click is going to be a normal one again
                m_possibleDoubleClick = false;
               
                // Correct the caret position if the click was to the right of the end of line
                if (m_lines[m_selStart.y].getSize() > 1 && (m_selStart.x == (m_lines[m_selStart.y].getSize()-1) || m_selStart.x == m_lines[m_selStart.y].getSize()))
                {
                    m_selStart.x--;
                    m_selEnd.x = m_selStart.x;
                }
               
                if (isWhitespace(m_lines[m_selStart.y][m_selStart.x]))
                {
                    // Select the space
                    ...


texus, will all of that were implemented in the future tgui's updates? ::) Cause it's very needful things, and I'd not like to do unnecessary inheritances or change sources every update ot other superfluous things. I think the other programmers too) ::)

And how about EditBox? Can I try to add to it similar events? Namely just three:
control
shift
double-click

texus

Quotewill all of that were implemented in the future tgui's updates?
As soon as we both confirm that the changes are working then the changes will be added in tgui.

Could you send the full TextBox.cpp file so that we have the exact same version?

QuoteAnd how about EditBox? Can I try to add to it similar events?
Sure, feel free to change it too.

Myster

#20
No problem, the file attached.
I meant in any future and any update and even with any other code, etc.  I understand that it even may take time testing) Just to be comfortable control that will not scare the users of future applications)

QuoteSure, feel free to change it too.
Ok, I try if tomorrow will be a time. I hope)

texus

#21
I made one more change to the code. You only selected a single space when double clicking, but if there are multiple whitespace next to each other then they should all be selected. I basically just reused the code that you wrote to select the entire word and made it do the inverse as well to select the whitespaces.

If you have a github account and know how to do it then you could send a pull request with the changes. Otherwise I will just commit the change myself but with your name on it. But I would need your name and email that you want on the git commit.

Quotetexus, will all of that were implemented in the future tgui's updates? ::) Cause it's very needful things, and I'd not like to do unnecessary inheritances or change sources every update ot other superfluous things. I think the other programmers too) ::)
QuoteI meant in any future and any update and even with any other code, etc.  I understand that it even may take time testing) Just to be comfortable control that will not scare the users of future applications)
I don't fully understand these sentences, so if there was still a question in it you should try to rephrase it.

Myster

#22
No, you understood correctly. And you've already answered my question) Thank you :)

Quoteif there are multiple whitespace next to each other then they should all be selected
I updated with your changes. You right, it's better. Just now I noticed that in my Notepad++ implemented multiple space selection.

No. Unfortunately, still I don't have an account on the github. In fact, I think I gave the basic idea, but you made a substantial part of it. I mean, not sure that my work here has the weight and whether it is worth to mention me.
But all at your discretion) I'm thankful for all.
My surname and name (with transliteration): Ilyin Mikhail
E-mail: ilyin_my @ mail.ru (without spaces, it's for spam :) )

And yet all the innovations are stable. I've not bumped into bugs or crashes. But I'll let you know if something will (I hope not). I will test my app as a user, and the continuous work will show itself.
Maybe some features I forgot (my feeling). But now they are not significant, if I can't remember)

Myster

#23
Yes! I remembered! Can you add this line, please?

Code (cpp) Select
            else // No double clicking
            {
                if (!(sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) || sf::Keyboard::isKeyPressed(sf::Keyboard::RShift)))
                    m_selStart = caretPosition;
                m_selEnd = caretPosition;


In the "leftMousePressed" function are no events, but in order not to overload with event links it easier to make the line a bit longer?
In any case, I just remember that "Shift + LeftMouseClick" is comfortable too.  ::)

texus

#24
The changes (including the one you just asked to add) have been added to tgui.

The changes wouldn't be made at all if you didn't start them, and the code that I improved was always still based on what you wrote, so I think you do deserve the credit.

Myster

Thank you very much! :)
Remains only "space furl", but I agree that's problem in code from other places and not so easy. If there are any ideas, I will say.

I'll try to do something with the EditBox, but a bit studying, I knew that there is almost everywhere a different structure. While I did not even know at what stage the text selection.