SFML community forums

Help => General => Topic started by: Foz44 on February 05, 2020, 06:03:40 am

Title: [SOLVED]basic text box
Post by: Foz44 on February 05, 2020, 06:03:40 am
If I were relatively new to C++ and SFML and were looking for a way to incorporate into my game a text box for user input - something vaguely like a dos shell - would there be a tutorial or guide you might suggest?
Title: Re: basic text box
Post by: Fx8qkaoy on February 06, 2020, 10:12:25 am
If I were relatively new to C++ and SFML and were looking for a way to incorporate into my game a text box for user input - something vaguely like a dos shell - would there be a tutorial or guide you might suggest?

DOS shell with SFML? U could make an array of text. When receiving input and shell on focus, append the char to last text obj. On new line u could remove from top of array an obj and add at end another one. I recommend having some exp with C++ before diving in cause is not easy for beginners (maybe)
Title: Re: basic text box
Post by: Foz44 on February 07, 2020, 05:08:29 am
I found most of what I needed in an old post - I can now save user input into a string and 'echo' each char to the screen at the location of a prompt like I want:

 while (window.pollEvent(e)) {
     if (e.type == Event::KeyPressed) {              
         if (e.type == Event::TextEntered) {
              if (e.text.unicode < 128) {
                  input += static_cast<char>(e.text.unicode);
                  output.setFillColor(Color::White);
                  output.setString(input);
              }
          }
      }
.
.
.
window.draw(prompt);
window.draw(output);

What I need now is a way to make the 'backspace' button work like it's supposed to. Will I have to manually pop a char off the end of the string for each "Keyboard::Backspace" detected, or does SFML have something for that?
Title: Re: basic text box
Post by: Fx8qkaoy on February 07, 2020, 06:30:55 am
I found most of what I needed in an old post - I can now save user input into a string and 'echo' each char to the screen at the location of a prompt like I want:

 while (window.pollEvent(e)) {
     if (e.type == Event::KeyPressed) {              
         if (e.type == Event::TextEntered) {
              if (e.text.unicode < 128) {
                  input += static_cast<char>(e.text.unicode);
                  output.setFillColor(Color::White);
                  output.setString(input);
              }
          }
      }
.
.
.
window.draw(prompt);
window.draw(output);

What I need now is a way to make the 'backspace' button work like it's supposed to. Will I have to manually pop a char off the end of the string for each "Keyboard::Backspace" detected, or does SFML have something for that?

If u have a std::string called input which u use to set the Text object, then u need to pop the last char from std::string. There is a fuction substr for std::string which will return a substring (basically u cut the string)
Title: Re: basic text box
Post by: Foz44 on February 08, 2020, 04:03:22 am
OK, "input = input.supstr(0, input.size() - 2)" was the answer. (I had to make it "input.size() - "2" instead of "1" so that it would also remove the strange character that the BackSpace key itself made.) Thank you, Fx8akaoy, for the help.

For the benefit of anyone else not very familiar with C++ strings who may come across this thread, the internet says that std::string::pop_back() would do exactly what I needed. It did not work at all...
Title: Re: [SOLVED] basic text box
Post by: Laurent on February 08, 2020, 10:30:41 am
You need to filter out non-printable characters in the TextEntered event, so that, for example, backspace doesn't add an unwanted character to your string. And once your string only contains printable characters, you won't have to erase 2 characters, and you can use std::string::pop_back, which is much more efficient than using substr.
Title: Re:basic text box
Post by: Foz44 on February 13, 2020, 09:45:50 pm
Just when I thought it was safe to go back into the water...<i'm returning this to 'unsolved'>. I originally thought I was doing just that with the line "if(text.unicode < 128)", until I saw that the Unicode for the 'BackSpace' key is '8'. And nothing I've seen yet on the internet is very clear, so just how DO I filter out non-printable characters?
Title: Re:basic text box
Post by: Fx8qkaoy on February 14, 2020, 07:38:32 am
Just when I thought it was safe to go back into the water...<i'm returning this to 'unsolved'>. I originally thought I was doing just that with the line "if(text.unicode < 128)", until I saw that the Unicode for the 'BackSpace' key is '8'. And nothing I've seen yet on the internet is very clear, so just how DO I filter out non-printable characters?

Take a look at the ASCII table
Title: Re: basic text box
Post by: Laurent on February 14, 2020, 07:49:02 am
std::isprint works fine for the ASCII range. For the rest of the Unicode world, you'd probably need a 3rd party library.
Title: Re: basic text box
Post by: Mortal on February 14, 2020, 08:00:12 am
it quite easy to retrieve all ASCII characters programmatically, just run a for-loop to print out all characters that range from 0 to 255. unless i misunderstood what you are trying to achieve.

for (int i = 0; i < 255; i++)
    std::cout << i << ' ' << (char)i << '\n';
Title: Re: basic text box
Post by: Foz44 on February 14, 2020, 10:58:14 pm
Sorry - I'll try to give a better picture of what I'm after. I wanted to simulate the basic construct of the old msdos ui, where the user can type simple commands at the C:\ prompt, for example, and bring up various menus. At first I thought I found exactly what I needed with the example:

while (window.pollEvent(e)) {
     if (e.type == Event::KeyPressed) {             
         if (e.type == Event::TextEntered) {
              if (e.text.unicode < 128) {
                  input += static_cast<char>(e.text.unicode);

from my previous messages: I could use the 'input' variable to echo the characters back to the screen as the user typed them as well as add to input's position.y to bring the prompt down to the next line whenever Unicode 8 (return key) was detected, for example. the problem I'm having is that certain keys (the BackSpace key - Unicode 8, in my case) add unwanted characters to the 'input' string. What I need is to parse the string in such a way that only pure, printable char's are left. That way I could, among other things, use code such as:  if(input == "list") { MyClass.displayList(); }, or - as Laurent pointed out - use the more efficient string::pop_back() when the user presses BackSpace instead of 'substr()' that I have to use now...
Title: Re: basic text box
Post by: Mortal on February 15, 2020, 07:51:53 am
The for-loop will tell you all information you need, the printable ASCII characters and its index position For example:If i run the for-loop in my PC it will print something like this:

30 �
31 �
32 
33 !
34 "
35 #
36 $
37 %
 ........
122 z
123 {
124 |
125 }
126 ~
127 
128 �
129 �


From the output, we can easily now detect all of printable chars and its indices which is clearly the printable chars start from index 32 upto 127. now, we need to add this boundary check to SFML event-loop:

//if (event.text.unicode >= 32 && event.text.unicode <= 127)
if (std::isprint(event.text.unicode)) // thanks to Laurent
    input_text += event.text.unicode;

Don't worry about if user press BackSpace or Return/Enter keys, sf::Text will take care for these inputs internally, just supply the string to sf::Text::setString with escape char in event-loop:

if (event.key.code == sf::Keyboard::BackSpace) {
    if (!input_text.empty())
        input_text.pop_back();// as Laurent pointed out
        //input_text.erase(--input_text.end());
}
if (event.key.code == sf::Keyboard::Return){
        input_text += '\n';
}


That's it, we have accomplished a minimal text editor.

I added a simple blinking effect to “cursor”. It was a part of my early demos when I was working out with the SFML library. ;D


Here the complete source source:
#include <SFML/Graphics.hpp>
#include <locale>

int main()
{
    sf::RenderWindow window({ 640 ,480 }, "test");

    std::string input_text;
    sf::Font font;
    font.loadFromFile("resources/font.ttf");
    sf::Text text("", font);

    sf::Clock clock;

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
            else if (event.type == sf::Event::TextEntered) {
                if (std::isprint(event.text.unicode))
                    input_text += event.text.unicode;
            }
            else if (event.type == sf::Event::KeyPressed) {
                if (event.key.code == sf::Keyboard::BackSpace) {
                    if (!input_text.empty())
                        input_text.pop_back();
                }
                if (event.key.code == sf::Keyboard::Return) {
                        input_text += '\n';
                }
            }
        }

        static sf::Time text_effect_time;
        static bool show_cursor;

        text_effect_time += clock.restart();

        if (text_effect_time >= sf::seconds(0.5f))
        {
            show_cursor = !show_cursor;
            text_effect_time = sf::Time::Zero;
        }

        text.setString(input_text + (show_cursor ? '_' : ' '));

        window.clear();
        window.draw(text);
        window.display();
    }
}
Title: Re: basic text box
Post by: Laurent on February 15, 2020, 09:18:02 pm
Or use std::isprint and rely on the standard library, instead of trying to reverse-engineer the ASCII table.
Title: Re: basic text box
Post by: Mortal on February 15, 2020, 10:01:30 pm
excellent point Laurent.
yes, indeed, it's quite useful, gotta update my code example.
Title: Re: basic text box
Post by: Laurent on February 16, 2020, 09:37:58 am
You may still need the < 128 check, because I don't think std::isprint is defined on the whole Unicode range. It may not even use the current locale, so only the ASCII range would be safe to test. Anyway, its documentation should be read to sort out these details.
Title: Re: basic text box
Post by: Foz44 on February 17, 2020, 04:34:18 am
Thank you very much for the advice - I'll give it a shot... 8)