← index
MasterX_System/system/src/mx_controls.cpp
Source: MasterX_System/system/src/mx_controls.cpp
#include "mx_controls.hpp"

#include "mx_window.hpp"


namespace mx {

       Label::Label(mxApp &app)
        : font_(nullptr), name_(""), text_(""), x(0), y(0), size_(0), wx(0), wy(0), w(0), h(0) {
            parent = nullptr;
        }

    Label::~Label() {
        if(font_ != nullptr)
            TTF_CloseFont(font_);
    }

    void Label::setWindowPos(int xx, int yy) {
        wx = xx;
        wy = yy;
    }

    void Label::draw(mxApp &app) {

        if(!show)
            return;


        if(font_ != nullptr && text_.length() > 0 && multi_lined == false) {
            if(mode == false || under_ == false) {
                TTF_SetFontStyle(font_, TTF_STYLE_NORMAL);
            } else if(under_ == true) {
                cursor_shown = true;
                TTF_SetFontStyle(font_, TTF_STYLE_UNDERLINE);
            }

            SDL_Surface *surf = TTF_RenderText_Blended(font_, text_.c_str(), color_);
            if(surf == nullptr) {
                mx::system_err << "MasterX System: Error creating surface.\n";
                mx::system_err.flush();
                return;
            }
            int sw = surf->w;
            int sh = surf->h;
            w = sw;
            h = sh;
            SDL_Texture *t = SDL_CreateTextureFromSurface(app.ren, surf);
            if(t == nullptr) {
                mx::system_err << "MasterX System: Error creating texture.\n";
                mx::system_err.flush();
                return;
            }
            SDL_FreeSurface(surf);
            SDL_SetRenderTarget(app.ren, app.tex);
            SDL_Rect point = {x+wx,y+wy+25,sw,sh};
            SDL_RenderCopy(app.ren, t, nullptr, &point);
            SDL_DestroyTexture(t);

        } else if(font_ != nullptr && multi_text.size()>0 && multi_lined == true) {
            int off_y = 0;
            int height = TTF_FontHeight(font_);
                
            for(int i = 0; i < static_cast<int>(multi_text.size()); ++i) {
                if(multi_text[i].length()==0) continue;
                SDL_Surface *surf = TTF_RenderText_Blended(font_, multi_text[i].c_str(), color_);
                if(surf == nullptr) {
                    mx::system_err << "MasterX System: Error creating surface.\n";
                    mx::system_err.flush();
                    return;
                }
                int sw = surf->w;
                int sh = surf->h;
                w = sw;
                h = sh;
                SDL_Texture *t = SDL_CreateTextureFromSurface(app.ren, surf);
                if(t == nullptr) {
                    mx::system_err << "MasterX System: Error creating texture.\n";
                    mx::system_err.flush();
                    return;
                }
                SDL_FreeSurface(surf);
                SDL_SetRenderTarget(app.ren, app.tex);
                SDL_Rect point = {x+wx,y+wy+25+off_y+height,sw,sh};
                SDL_RenderCopy(app.ren, t, nullptr, &point);
                SDL_DestroyTexture(t);
                off_y += height;
            }
        }
    }

    void Label::linkMode(bool m) {
        mode = m;
    }

    void Label::create(Window *parent, const std::string &text, SDL_Color col, int xx, int yy) {
        setText(text, col);
        setGeometry(xx, yy);
        this->parent = parent;
        multi_lined = false;
        color_ = col;
    }
    
    void Label::create_multi(Window *parent, std::vector<std::string>  &t, SDL_Color col, int xx,  int yy) {
        setMultiLine(t);
        setGeometry(xx,yy);
        this->parent = parent;
        multi_lined = true;
        color_ = col;
    }

    bool Label::event(mxApp &app, SDL_Event &e) {

        if(!show) return false;

        if(e.type == SDL_MOUSEMOTION) {
            int mx = e.motion.x;
            int my = e.motion.y;
            SDL_Rect rc = {x+wx, y+wy+25, w, h };
            SDL_Point cp = { mx, my };
            if(SDL_PointInRect(&cp, &rc)) {
                cursor_shown = true;
                under_ = true;
                return true;
            } else {
                under_ = false;
            }
        }


        return false;
    }

    void Label::setMultiLine(std::vector<std::string> &v) {
        multi_text = std::move(v);
    }

    void Label::loadFont(const std::string &name, int sizex) {
        name_ = name;
        size_ = sizex;
        font_ = TTF_OpenFont(getPath(name).c_str(), size_);
        if(font_ == nullptr) {
            mx::system_err << "Error opening font: " << getPath(name) << "\n";
            mx::system_err.flush();
            exit(EXIT_FAILURE);
        }
    }

    void Label::setText(const std::string &text, SDL_Color col) {
        text_ = text;
        color_ = col;
    }

    void Label::setGeometry(int xx, int yy) {
        x = xx;
        y = yy;
    }

    Button::Button(mxApp &app) 
        : x(0), y(0), w(0), h(0),wx(0), wy(0), hover(false), pressed(false) {
        fgColor = { 200, 200, 200, 255 };  
        bgColor = { 240, 240, 240, 255 };  
        hover_fg = { 180, 180, 180, 255 };  
        hover_bg = { 220, 220, 220, 255 };  
        pressed_fg = { 120, 120, 120, 255 };  
        pressed_bg = { 200, 200, 200, 255 };  
        textColor = { 0, 0, 0, 255 };        
        parent = nullptr;
    }

    Button::~Button() {}

    void Button::draw(mxApp &app) {
        if (!show) return;

        SDL_Renderer* renderer = app.ren;
        SDL_Rect rect = { x+wx, y+wy, w, h };
        
        SDL_Color topLeftColor = fgColor;
        SDL_Color bottomRightColor = { 100, 100, 100, 255 };  

        if (pressed) {
            SDL_SetRenderDrawColor(renderer, pressed_bg.r, pressed_bg.g, pressed_bg.b, pressed_bg.a);
            topLeftColor = pressed_fg;
            bottomRightColor = { 150, 150, 150, 255 }; 
        } else if (hover) {
            SDL_SetRenderDrawColor(renderer, hover_bg.r, hover_bg.g, hover_bg.b, hover_bg.a);
        } else {
            SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, bgColor.a);
        }
        
        SDL_RenderFillRect(renderer, &rect);
        
        int cx = x + wx;
        int cy = y + wy;
        
        SDL_SetRenderDrawColor(renderer, topLeftColor.r, topLeftColor.g, topLeftColor.b, topLeftColor.a);
        SDL_RenderDrawLine(renderer, cx, cy, cx + w - 1, cy);  
        SDL_RenderDrawLine(renderer, cx, cy, cx, cy + h - 1);  
        
        SDL_SetRenderDrawColor(renderer, bottomRightColor.r, bottomRightColor.g, bottomRightColor.b, bottomRightColor.a);
        SDL_RenderDrawLine(renderer, cx + w - 1, cy, cx + w - 1, cy + h - 1);  
        SDL_RenderDrawLine(renderer, cx, cy + h - 1, cx + w - 1, cy + h - 1);  

        if (app.font) {
            SDL_Surface* surface = TTF_RenderText_Blended(app.font, text.c_str(), textColor);
            SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);

            int text_width = surface->w;
            int text_height = surface->h;
            SDL_Rect dstrect = { cx + (w - text_width) / 2, cy + (h - text_height) / 2, text_width, text_height };

            SDL_RenderCopy(renderer, texture, nullptr, &dstrect);

            SDL_FreeSurface(surface);
            SDL_DestroyTexture(texture);
        }
    }

    void Button::setWindowPos(int xx, int yy) {
        wx = xx;
        wy = yy;
    }

    bool Button::event(mxApp &app, SDL_Event &e) {

        int cx = x + wx;
        int cy = y + wy;

        if (e.type == SDL_MOUSEMOTION) {
            int mouseX = e.motion.x;
            int mouseY = e.motion.y;
            hover = (mouseX >= cx && mouseX <= cx + w && mouseY >= cy && mouseY <= cy + h);
        }

        if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT) {
            int mouseX = e.button.x;
            int mouseY = e.button.y;
            if (mouseX >= cx && mouseX <= cx + w && mouseY >= cy && mouseY <= cy + h) {
                pressed = true;
              
            }
        }

        if (e.type == SDL_MOUSEBUTTONUP && e.button.button == SDL_BUTTON_LEFT) {
            int mouseX = e.button.x;
            int mouseY = e.button.y;
            if (pressed && mouseX >= cx && mouseX <= cx + w && mouseY >= cy && mouseY <= cy + h) {
                pressed = false;
                if(callback && parent) {
                    return callback(app, parent, e);
                }
                return true;  
            }
            pressed = false;
        }
        
        return false;
    }

    void Button::create(Window *parent, const std::string &text, int x, int y, int w, int h) {
        this->text = text;
        this->x = x;
        this->y = y;
        this->w = w;
        this->h = h;
        this->parent = parent;
    }

    void Button::setText(const std::string &t) {
        text = t;
    }

    void Button::setGeometry(int xx, int yy, int ww, int hh) {
        x = xx;
        y = yy;
        w = ww;
        h = hh;
    }
 
    void Button::resizeWindow(int w, int h) {
        if(rcallback && parent) {
            rcallback(parent, w, h);
        }
    }

    Image::Image(mxApp &app) : x(0), y(0), w(0), h(0), image(nullptr) {

    }

    Image::~Image() {
        if(image) {
            SDL_DestroyTexture(image);
        }
    }

    void Image::setWindowPos(int x, int y) {
        wx = x;
        wy = y;
    }

    void Image::draw(mxApp &app) {

        if(!show)
            return;

        if(image) {
            int dw = w, dh = h;
            if(w == 0 || h == 0) {
                dw = sw;
                dh = sh;
            }
            SDL_Rect rc = { x+wx, y+wy+25, dw, dh };
            SDL_RenderCopy(app.ren, image, (use_rect == true) ? &src : nullptr, &rc);
        }
    }

    void Image::getRect(SDL_Rect &rc) {
        rc.x = x;
        rc.y = y;
        rc.w = w;
        rc.h = h;
    }

    bool Image::event(mxApp &app, SDL_Event &e) {
        if(show == false)
            return false;
        int cx = x + wx;
        int cy = y + wy;
        if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT) {
            int mouseX = e.button.x;
            int mouseY = e.button.y;
            if (mouseX >= cx && mouseX <= cx + w && mouseY >= cy && mouseY <= cy + h) {
                if(callback && parent) {
                    return callback(app, parent, e);
                }
                return true;       
            }
        }
        return false;
    }

    void Image::create(mxApp &app, Window *window, const std::string &path, int x, int y) {
        image = loadTexture(app, path, sw, sh);
        parent= window;
        this->x = x;
        this->y = y;
        w = sw;
        h = sh;
    }

    void Image::setSourceRect(int x, int y, int w, int h) {
        src.x = x;
        src.y = y;
        src.w = w;
        src.h = h;
        use_rect = true;
    }

    void Image::setGeometry(int x, int y, int w, int h) {
        this->x = x;
        this->y = y;
        this->w = w;
        this->h = h;
    }    

    void Image::resizeWindow(int w, int h) {
        setGeometry(x, y, w, h);  
    }
}