Image support

This commit is contained in:
2025-11-02 17:48:43 +00:00
parent 93ba953738
commit 9aae7b6173
5 changed files with 77 additions and 11 deletions

View File

@@ -1,5 +1,6 @@
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <SDL3_image/SDL_image.h>
#include <iostream>
#include <utility>
#include <variant>
@@ -21,7 +22,27 @@ namespace Quip {
SDL_DestroySurface(surface);
}
Button::Button(std::string text, std::function<void()> callback, int xpos, int ypos) : text(std::move(text)), callback(std::move(callback)), xpos(xpos), ypos(ypos) {}
Image::Image(const std::string& filepath, int xpos, int ypos, int width, int height) : width(width), height(height), xpos(xpos), ypos(ypos) {
surface = IMG_Load(filepath.c_str());
if (surface == nullptr) {
Window().error(4, "Couldn't load image " + filepath);
}
if (width < 0) {
this->width = surface->w;
}
if (height < 0) {
this->height = surface->h;
}
}
void Image::render(const Window &window) const {
SDL_Texture* texture = SDL_CreateTextureFromSurface(window.renderer, surface);
SDL_FRect destRect = {static_cast<float>(xpos), static_cast<float>(ypos), static_cast<float>(width), static_cast<float>(height)};
SDL_RenderTexture(window.renderer, texture, nullptr, &destRect);
SDL_DestroyTexture(texture);
}
Button::Button(std::string text, std::function<void()> callback, int xpos, int ypos) : text(std::move(text)), onCLick(std::move(callback)), xpos(xpos), ypos(ypos) {}
void Button::render(const Window &window) const {
SDL_SetRenderDrawColor(window.renderer, 40, 60, 80, 255); // Dark gray background
SDL_FRect backgroundRect = {static_cast<float>(xpos), static_cast<float>(ypos), static_cast<float>(width), static_cast<float>(height)};
@@ -38,7 +59,7 @@ namespace Quip {
}
Window::Window() = default;
Window::Window(std::string title, int width, int height) : title(std::move(title)), width(width), height(height) {
Window::Window(std::string title, int width, int height, const std::function<void()>& onFrame) : title(std::move(title)), width(width), height(height), onFrame(onFrame) {
windowCount ++;
if (width <= 0 || height <= 0) {
error(2, "width is " + std::to_string(width) + " and height is " + std::to_string(height));
@@ -60,7 +81,7 @@ namespace Quip {
}
}
void Window::error(int errCode, const std::string& context) {
void Window::error(int errCode, const std::string& context) const {
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
@@ -79,6 +100,9 @@ namespace Quip {
case 3:
std::cerr << "Widget name error" << std::endl;
break;
case 4:
std::cerr << "File error" << std::endl;
break;
}
if (!context.empty()) {
std::cerr << "Context: " << context << std::endl;
@@ -97,6 +121,8 @@ namespace Quip {
case 3:
throw std::runtime_error("Quip::Window() Widget name error");
break;
case 4:
throw std::runtime_error("Quip::Window() File error");
}
}
@@ -117,6 +143,7 @@ namespace Quip {
int Window::run() {
while (true) {
onFrame();
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_EVENT_QUIT:
@@ -133,8 +160,8 @@ namespace Quip {
// Check if click is inside button bounds
if (mouseX >= button.xpos && mouseX <= button.xpos + button.width &&
mouseY >= button.ypos && mouseY <= button.ypos + button.height) {
if (button.callback) {
button.callback();
if (button.onCLick) {
button.onCLick();
}
}
}
@@ -149,6 +176,8 @@ namespace Quip {
std::get<Widget::TextLabel>(widget).render(*this);
} else if (std::holds_alternative<Widget::Button>(widget)) {
std::get<Widget::Button>(widget).render(*this);
} else if (std::holds_alternative<Widget::Image>(widget)) {
std::get<Widget::Image>(widget).render(*this);
}
}
if (!SDL_RenderPresent(renderer)) {

View File

@@ -2,6 +2,7 @@
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#include <SDL3_image/SDL_image.h>
#include <string>
#include <variant>
#include <functional>
@@ -19,17 +20,25 @@ namespace Quip {
explicit TextLabel(std::string text, int xpos, int ypos);
TextLabel();
};
class Image {
SDL_Surface* surface;
public:
int width = 0, height = 0;
int xpos = 0, ypos = 0;
void render(const Window &window) const;
Image(const std::string& filepath, int xpos, int ypos, int width = -1, int height = -1);
};
class Button {
public:
std::string text;
std::function<void()> callback;
std::function<void()> onCLick;
int xpos = 0, ypos = 0;
int width = 100, height = 30;
void render(const Window &window) const;
explicit Button(std::string text, std::function<void()> callback, int xpos, int ypos);
};
typedef std::variant<TextLabel, Button> Widget;
typedef std::variant<TextLabel, Button, Image> Widget;
}
class Window {
@@ -41,11 +50,12 @@ namespace Quip {
std::string title;
int width, height;
std::map<std::string, Widget::Widget> widgets;
void error(int errCode = 0, const std::string& context = "");
std::function<void()> onFrame;
void error(int errCode = 0, const std::string& context = "") const;
int run();
void addChild(const std::string& id, const Widget::Widget& widget);
Widget::Widget* getChild(const std::string& id);
explicit Window(std::string title, int width = 800, int height = 600);
explicit Window(std::string title, int width = 800, int height = 600, const std::function<void()>& onFrame = nullptr);
Window();
};