← index
libmx2/libmx/controller_test/main.cpp
Source: libmx2/libmx/controller_test/main.cpp
#include"mx.hpp"

#include<algorithm>

#include<unordered_map>

#include<chrono>

#include<sstream>

#ifdef __EMSCRIPTEN__

#include <emscripten/emscripten.h>

#endif


class Intro : public obj::Object {
public:
    Intro() = default;
    ~Intro() override {}

    virtual void load(mx::mxWindow *win) override {
        font.loadFont(win->util.getFilePath("data/font.ttf"), 18);
        pos_x = 25;
        pos_y = win->height/2-(24/2);
        win_width = win->width;
        win_height = win->height;
        updateTitle(win);
    }

    virtual void draw(mx::mxWindow *win) override {
        SDL_Rect rect = { pos_x, pos_y, square_size, square_size };
        SDL_SetRenderDrawColor(win->renderer, 255, 255, 255, 255);
        SDL_RenderFillRect(win->renderer, &rect);
        std::ostringstream stream;
        if(controller.active()) {
            stream <<"Controller: " << controller.name() << " connected at port: " << controller.controllerIndex();
        } else {
            stream << "Connect a controller";
        }
        win->text.printText_Blended(font, 10, 10, stream.str());
        auto now = std::chrono::steady_clock::now();
        for (auto &[button, timestamp] : buttonState) {
            auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - timestamp).count();
            if (elapsed >= repeat_delay) {
                handleButtonRepeat(button);
                buttonState[button] = now; 
             }
        }
    }

    virtual void event(mx::mxWindow *win, SDL_Event &e) override {
        auto now = std::chrono::steady_clock::now();

        if(controller.connectEvent(e)) {
            updateTitle(win);
        }

        if (e.type == SDL_CONTROLLERBUTTONDOWN) {
            buttonState[e.cbutton.button] = now; 
        }

        if (e.type == SDL_CONTROLLERBUTTONUP) {
            buttonState.erase(e.cbutton.button); 
        }
    }

private:

    void updateTitle(mx::mxWindow *win) {
        if(!controller.active())
            win->setWindowTitle("-[ Connect Controller ]-");
        else
            win->setWindowTitle("-[ Controller Connected ]-");
    }

    void handleButtonRepeat(Uint8 button) {
        if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
            pos_y -= movement_speed;
        } else if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
            pos_y += movement_speed;
        } else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
            pos_x -= movement_speed;
        } else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
            pos_x += movement_speed;
        }

        pos_x = std::max(0, std::min(win_width - square_size, pos_x));
        pos_y = std::max(0, std::min(win_height - square_size, pos_y));
    }

    int pos_x = 0, pos_y = 0;
    const int square_size = 50;
    const int movement_speed = 10;
    const int repeat_delay = 15; 
    int win_width = 640, win_height = 480;

    mx::Controller controller;
    mx::Font font;
    std::unordered_map<Uint8, std::chrono::steady_clock::time_point> buttonState;
};


class MainWindow : public mx::mxWindow {
public:
    MainWindow(const std::string &path) : mx::mxWindow("Controller Test", 960,  720, false) {
        setPath(path);
        setObject(new Intro());
        object->load(this);
    }
    
     ~MainWindow() override {

     }

    virtual void event(SDL_Event &e) override {
        
    }

    virtual void draw(SDL_Renderer *renderer) override {
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        // draw

        object->draw(this);
        SDL_RenderPresent(renderer);
    }
};


MainWindow *main_w = nullptr;

void eventProc() {
    main_w->proc();
}

int main(int argc, char **argv) {
#ifdef __EMSCRIPTEN__

    MainWindow main_window("/");
    main_w =&main_window;
    emscripten_set_main_loop(eventProc, 0, 1);
#else

    try {
        std::string path = ".";
        if(argc == 2) {
            path = argv[1];    
        } else {
            mx::system_err << "Requires one argument, being path to resouces...\n";
            mx::system_out << "Trying default path . \n";
            path = ".";
        }
        MainWindow main_window(path);
        main_window.loop();
    } 
    catch(const mx::Exception &e) {
        mx::system_err << "mx: Exception: " << e.text() << "\n";
        mx::system_err.flush();
        exit(EXIT_FAILURE);
    }
#endif


    return 0;
}