Getting started

Initial setup

To use the library, include the component-sdl2 header file:

#include <component-sdl2>

The library is located in the Kit namespace, and in order not to write Kit::* each time, the following line will be implied in the following examples:

using namespace Kit;

The main function must take two parameters int , char **!

After connecting the library, access to the library object is via the $ variable. To start the library, you need to call the run method.

So the simplest code would look like this:

#include <component-sdl2>
using namespace Kit;

int main(int argc, char** argv)
{
    return $.run();
}

Adding Windows

The main method of the main library class is addWindow, which is used to add windows. It has the following form:

Window* addWindow(Window* window);

The Window class is the base class for any application window. It has a single constructor:

// SimpleRect is struct { x, y, w, h }
Window(std::string title, SimpleRect size, noBorder = false);

The first parameter is the window title, the second is the size and position of the window (specifying -1 in the position coordinates aligns the window in the center), and the third is a flag indicating whether the window will have a standard frame.

Let's see how to add a window:

#include <component-sdl2>
using namespace Kit;

int main(int, char**)
{
    $.addWindow(new Window("Test Window", { -1, -1, 300, 300 }, false));
    return $.run();
}

As a result, an empty window will be displayed in the center with a size of 300 by 300 pixels.

Adding Components

There are several ways to add new components to a window. The first way is to add components to the main function. To add components, use the add method.

The add method has several prototypes:

Component* add(const string& id, const string& classes, 
               const vector<Component*>& childrens = {});

Component* add(const string& classes = "", 
               const vector<Component*>& childrens = {});

Component* add(Component* component);

The first prototype, as the most common.

The method takes the identifier string of the component as the first parameter (identifiers must begin with the # character!). In this case, the window cannot contain two components with the same identifier!

The second parameter is a string of class identifiers separated by a space. (class identifiers must begin with . character!). Class identifiers, in contrast to ordinary identifiers, can be repeated from component to component.

The third parameter is an optional vector of child components. Usually, to add components, you can use just calling new Component (...), but it is better to use the static create method of the Component class. This method completely repeats the add method discussed above.

The second prototype differs only in that it does not accept an identifier. This prototype will generate a random identifier for the component, which may be convenient in some cases.

The third prototype simply accepts a pointer to a Component. This prototype will be used when adding standard components (Button, Checkbox, etc.). Usually, as with the child components from the second prototype, it is better to use the create method on the Component class or on standard component classes.

Example

Let's add the components in the first way:

#include <component-sdl2>
using namespace Kit;

int main(int, char**)
{
    auto window = $.addWindow(new Window("Test Window", { -1, -1, 300, 300 }, false));

    // add a simple component
    window->add("#test", ".test");

    // add component with child components
    window->add("#test-childs", ".test", {
        Component::create("#inner", ".inner"),
        Component::create("#inner-1", ".inner", {
            Component::create("#inner-inner", ".inner-inner")
        })
    });


    return $.run();
}

So far, if you run the program, nothing will change from the last run without components. This is because the components in the window exist, but are not stylized!

Component Styling

The library uses css to style components. Each window can store the styles of all its components. To add a css file, use the style method:

void style(const string& path);

The path to the css file must be relative to the executable!

Example

Add the css folder in the same folder as main.cpp, and add the style.css file to it. And add the following code to it:

.test
{
    width: 70px;
    height: 24px;

    top: 100px;
    left: 100px;

    background-color: #263238;
    outline: #0F1518;
}

What happens here? First, all styles are set for class identifiers, which allows you to reuse styles from different components. Second, size and position are set using standard css attributes. More information about what values ​​these attributes can take in the css section. Third, the background color and the color of the single-pixel stroke are set, more about these and other possible properties in the css section.

Let's call the style method and write the path to the styles:

#include <component-sdl2>
using namespace Kit;

int main(int, char**)
{
    auto window = $.addWindow(new Window("Test Window", { -1, -1, 300, 300 }, false));

    // Add styles to the window
    window->style("../test/css/style.css");

    window->add("#test", ".test");

    return $.run();
}

After that, if you run the program, a rectangle with the specified dimensions with a stroke will appear in the window!

Extended styling

For more flexible style settings in different situations, the library allows you to use 3 css pseudo-classes.

The hover pseudo-class sets styles for the component that is currently hovering over the mouse.

The active pseudo-class sets styles for the component that the mouse button is clicked on.

The focus pseudo-class sets styles for the component that is currently in focus.

Pseudo-classes are defined as follows:

.classname:pseudo-classname
{ 
    
}

Adding components (preferred)

In many cases, adding components to windows in the first way is not convenient, and sometimes it is not advisable, for example, if you need to create two identical windows.

Especially for this, there is a second way. The second way is to inherit from the Window class.

Let's create a MyWindow in the same folder as main.cpp and add the MyWindow.h header file to it. To inherit, you must include the header file of the Window class.

#include "window/window.h"

Next, you need to create a class based on Window, add the constructor and the setup method, which is called in the constructor:

#pragma once

#include "window/window.h"
using namespace Kit;

class MyWindow : public Window
{
public:
    MyWindow(string title, SimpleRect size, bool noBorder = false)
        : Window(title, size, noBorder) 
    {
        setup();
    };

public:
    void setup()
    {

    }

};

The setup method is needed to configure the components in the window. Everything described in the first method also works here, let's rewrite the last example:

#pragma once

#include "window/window.h"
using namespace Kit;

class MyWindow : public Window
{
public:
    MyWindow(string title, SimpleRect size, bool noBorder = false)
        : Window(title, size, noBorder) 
    {
        setup();
    };

public:
    void setup()
    {
        style("../test/css/style.css");

        add("#test", ".test");
    }

};

Connect this window to main.cpp, and replace Window with MyWindow:

#include <component-sdl2>

#include "MyWindow/MyWindow.h"

using namespace Kit;

int main(int, char**)
{
    // создаем объект нестандартного окна
    $.addWindow(new MyWindow("Test Window", { -1, -1, 300, 300 }, false));

    return $.run();
}

Now, if you run the program, then we will get the same result as in the previous example. At the same time, we can create, for example, two windows with the same interface:

#include <component-sdl2>

#include "MyWindow/MyWindow.h"

using namespace Kit;

int main(int, char**)
{
    // create a custom window object
    $.addWindow(new MyWindow("Test Window", { -1, -1, 300, 300 }, false));
    // and one more
    $.addWindow(new MyWindow("Test Window 2", { 200, 200, 300, 300 }, false));

    return $.run();
}

Interaction with components.

Access to components by their id

To access the added components in the window, the static method getElementById of the Window class is used, where the identifier of the component is passed as the only parameter:

Component* getElementById(string id);

Adding text to a component

To set text, the Component class has a setText method. Add the text to the newly created component (we will only consider the setup method of the MyWindow):

void setup()
{
    style("../test/css/style.css");

    add("#test", ".test");

    Window::getElementById("#test")->setText("ok");
}

All styles for the text can be found in the css section.

Add event listeners

Components can track the following events:

To add a listener, use the addEventListener method, where the first argument is the name of the event that we are listening to, and the second is the function that will be called when this event occurs:

void addEventListener(const string& name_event, 
                      function<void(Component* sender, Event* e) callback>);

Example

Let's add a click event listener to our component using the lambda function:

void setup()
{
    style("../test/css/style.css");

    add("#test", ".test");

    Window::getElementById("#test")->addEventListener("click", 
    [](Component* sender, Event* e)
    {
        std::cout << "Component clicked" << std::endl;
    });
}

Now, when you click on a component, a message will be displayed in the console.

Removing a listener for an event

To remove the listener, use the removeEventListener method:

void removeEventListener(const string& action);

Additional information in the component

Any component can store additional information. To add, use the addUserData method:

void addUserData(string key, std::any data);

And to get information by key — userData method:

std::any userData(string key);

Last updated