SFML community forums

General => SFML projects => Topic started by: dabbertorres on March 30, 2014, 01:57:42 am

Title: Embedded Console
Post by: dabbertorres on March 30, 2014, 01:57:42 am
https://github.com/dabbertorres/EmbeddedConsole

This is a relatively simple embedded console in a RenderWindow. It takes advantage of C++11, especially in the use of std::function.

Current Features:

It only supports showing one prompt, input, and output right now, but plans are in place to remedy this limitation.
Here's a screenshot:
(http://i.imgur.com/HMx806m.png)

And an example of usage:
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>

#include "Console.hpp"

int main(int argc, char **argv)
{
    sf::RenderWindow window(sf::VideoMode(800, 600), "Console");

    sf::Font font;
    if(!font.loadFromFile("./data/DejaVuSansMono.ttf"))
        return 1;

    swift::Console console(500, 200, font);

    console.addCommand("mouse", [&window](std::vector<std::string> args)
    {
        if(args.size() == 2)
        {
            if(args[1] == "x")
                return "x: " + std::to_string(sf::Mouse::getPosition(window).x) + '\n';
            else if(args[1] == "y")
                return "y: " + std::to_string(sf::Mouse::getPosition(window).y) + '\n';
        }
        return "x: " + std::to_string(sf::Mouse::getPosition(window).x) + '\n'
        + "y: " + std::to_string(sf::Mouse::getPosition(window).y) + '\n';
    });

    console.addCommand("hello", [](std::vector<std::string> args)
    {
        return "Hello to you too!";
    });

    console.addCommand("exit", [&console](std::vector<std::string> args)
    {
        console.activate(false);
        return "";
    });

    while(window.isOpen())
    {
        sf::Event event;

        while(window.pollEvent(event))
        {
            switch(event.type)
            {
                case sf::Event::Closed:
                    window.close();
                    break;
                case sf::Event::TextEntered:
                    console.update(static_cast<char>(event.text.unicode));
                    break;
                case sf::Event::KeyPressed:
                    switch(event.key.code)
                    {
                        case sf::Keyboard::Up:
                            console.activate(false);
                            break;
                        case sf::Keyboard::Down:
                            console.activate(true);
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }

        window.clear(sf::Color::White);

        window.draw(console);

        window.display();
    }

    return 0;
}
Title: Re: Embedded Console
Post by: Kojay on March 30, 2014, 09:25:55 am
Remarks and ideas:

Title: Re: Embedded Console
Post by: Nexus on March 30, 2014, 11:08:35 am
I like the fact that one can simply bind lambda expressions to a command :)

std::function<const std::string(std::vector<std::string> args)>
Omit the const (returning a const object is a bad idea). Pass by value is fine, as long as you use move semantics (call std::move() to pass the vector), otherwise you copy unnecessarily. And I would use a typedef for the vector of strings, and maybe also for the function.

One thing to add would be functionality that helps with parsing and interpreting the command arguments.
Title: Re: Embedded Console
Post by: dabbertorres on March 30, 2014, 06:18:28 pm
Remarks and ideas:

  • No need to write Console's destructor.
  • It seems more natural to keep previous lines and pop as necessary (presumably your commented out deque was to that end?
  • line 65 of Console.cpp - instead of insert(make_pair()) can simply do commandList.emplace(c, f);
  • The states parameter isn't used in the draw function - either pass it to the draw calls or unname it.
  • line 41 of Console.cpp - gcc points out that t < 128 is always true
  • I would rather the commands the user registers return an ostream instead of a string - streaming makes for nicer syntax than string concatenation and you 're already using a stringstream in handleCommand.
  • Could Up and Down be used to cycle through command history instead?
  • (If you want to be really fancy) Provide autocomplete.

I like the fact that one can simply bind lambda expressions to a command :)

std::function<const std::string(std::vector<std::string> args)>
Omit the const (returning a const object is a bad idea). Pass by value is fine, as long as you use move semantics (call std::move() to pass the vector), otherwise you copy unnecessarily. And I would use a typedef for the vector of strings, and maybe also for the function.

One thing to add would be functionality that helps with parsing and interpreting the command arguments.
Thanks! I love lambdas. They make things so much easier/add so much more functionality (captures are awesome).
Alright, I was trying to show that the string wasn't going to be changed, and for dealing with temporaries.
Same deal with passing the vector and strings by value, avoiding the temporaries issue. And I thought move semantics was the default in C++11 (or is it for C++14?)?
I played with a typedef previously, since you think it's a good idea, I'll go through with it!

You don't think a vector is enough for that? I was trying to C++icize the int argc, char** argv argument handling. With a vector, one can use:
for(auto &a : args) {}
 
syntax, which is nice and to the point. Or am I misunderstanding you?

In any case, thanks for the remarks!
Title: Re: Embedded Console
Post by: Nexus on March 30, 2014, 07:14:30 pm
std::vector is good, but you may copy unnecessarily. Move semantics are not "default", they are only applied automatically for return values and temporaries, but not when passing arguments (since the values might still be used afterwards). In other situations, you  have to use std::move().
Title: Re: Embedded Console
Post by: dabbertorres on March 30, 2014, 10:12:27 pm
Ah I see, thanks for info.
Title: Re: Embedded Console
Post by: Dantez on March 31, 2014, 01:21:47 am
Function handleCommand doesn't handle blank command correctly (when just hitting enter).
Title: Re: Embedded Console
Post by: dabbertorres on March 31, 2014, 04:10:18 am
Oops, thanks for that, fixed and committed fix.
Title: Re: Embedded Console
Post by: dabbertorres on April 01, 2014, 08:07:12 pm
Multi-line support is now added (previous lines stay), horizontal wrap around is in place, and the text scrolls vertically as more commands and output happen.

The beginnings of using the Up and Down arrows for scrolling through history are in place as well.

Operator << has been added as well... Though it needs some refinement.