158 lines
4.6 KiB
C++
158 lines
4.6 KiB
C++
//
|
|
// Window.cpp
|
|
// gui
|
|
//
|
|
// Created by Bob Polis at 2020-10-14
|
|
// Copyright (c) 2020 SwiftCoder. All rights reserved.
|
|
//
|
|
|
|
#include <SDL2/SDL_image.h>
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
#include "Window.hpp"
|
|
#include "Image.hpp"
|
|
|
|
using namespace sc::gui;
|
|
|
|
std::vector<Window> Window::_windows;
|
|
std::map<SDL_WindowEventID, std::vector<WindowEventHandler>> Window::_global_event_handlers;
|
|
|
|
Window& Window::new_window(const std::string& title) {
|
|
_windows.emplace_back(title);
|
|
return _windows.back();
|
|
}
|
|
|
|
Window* Window::from_sdl(Uint32 window_id) {
|
|
SDL_Window* w {SDL_GetWindowFromID(window_id)};
|
|
if (w) {
|
|
auto it = std::find_if(_windows.begin(), _windows.end(), [w](Window& win) {
|
|
return win.window() == w;
|
|
});
|
|
if (it != _windows.end()) {
|
|
return &*it;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool Window::handle_window_event(const SDL_Event& event) {
|
|
bool quit {false};
|
|
Window* w {from_sdl(event.window.windowID)};
|
|
if (w) {
|
|
quit = w->handle_event(event, quit);
|
|
}
|
|
return quit | handle_global_event(event);
|
|
}
|
|
|
|
bool Window::handle_global_event(const SDL_Event& event) {
|
|
bool quit {false};
|
|
auto iter = _global_event_handlers.find(static_cast<SDL_WindowEventID>(event.window.event));
|
|
if (iter != _global_event_handlers.end()) {
|
|
for (WindowEventHandler handler : iter->second) {
|
|
quit = handler(event, quit);
|
|
}
|
|
}
|
|
switch (event.window.event) {
|
|
case SDL_WINDOWEVENT_CLOSE: {
|
|
// remove window from window list
|
|
SDL_Window* w {SDL_GetWindowFromID(event.window.windowID)};
|
|
auto it = std::remove_if(_windows.begin(), _windows.end(), [w](Window& win) {
|
|
return win.window() == w;
|
|
});
|
|
_windows.erase(it, _windows.end());
|
|
if (_windows.size() == 0) {
|
|
quit = true;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return quit;
|
|
}
|
|
|
|
void Window::add_global_event_handler(WindowEventHandler handler, SDL_WindowEventID type) {
|
|
auto it = _global_event_handlers.find(type);
|
|
if (it != _global_event_handlers.end()) {
|
|
it->second.push_back(handler);
|
|
} else {
|
|
std::vector<WindowEventHandler> handlers {handler};
|
|
_global_event_handlers.emplace(type, handlers);
|
|
}
|
|
}
|
|
|
|
Window::Window(const std::string& title) : _title {title} {
|
|
SDL_Window* win = SDL_CreateWindow(title.c_str(),
|
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
|
1600, 900,
|
|
SDL_WINDOW_RESIZABLE);
|
|
_w.reset(win);
|
|
_r.reset(SDL_CreateRenderer(win, -1, 0));
|
|
}
|
|
|
|
void Window::set_size(int w, int h) {
|
|
SDL_SetWindowSize(_w.get(), w, h);
|
|
}
|
|
|
|
void Window::update() const {
|
|
SDL_RenderClear(_r.get());
|
|
SDL_RenderCopy(_r.get(), _t.get(), nullptr, nullptr);
|
|
SDL_RenderPresent(_r.get());
|
|
}
|
|
|
|
void Window::show_image(const Image& image) {
|
|
// create texture from surface
|
|
_t.reset(SDL_CreateTextureFromSurface(_r.get(), image.surface()));
|
|
|
|
// get screen size, to scale down if image is too big
|
|
int w {image.width()};
|
|
int h {image.height()};
|
|
SDL_DisplayMode dm;
|
|
SDL_GetCurrentDisplayMode(0, &dm);
|
|
if (dm.w < w || dm.h < h) {
|
|
double screen_ratio {static_cast<double>(dm.w) / dm.h};
|
|
double image_ratio {static_cast<double>(w) / h};
|
|
const int safety {100}; // room for window and desktop adornments
|
|
if (screen_ratio > image_ratio) { // screen relatively less high than image
|
|
h = dm.h - safety;
|
|
w = static_cast<int>(round(image_ratio * h));
|
|
} else { // screen relatively less wide than image
|
|
w = dm.w - safety;
|
|
h = static_cast<int>(round(w / image_ratio));
|
|
}
|
|
}
|
|
set_size(w, h);
|
|
}
|
|
|
|
void Window::add_event_handler(WindowEventHandler handler, SDL_WindowEventID type) {
|
|
auto it = _event_handlers.find(type);
|
|
if (it != _event_handlers.end()) {
|
|
it->second.push_back(handler);
|
|
} else {
|
|
std::vector<WindowEventHandler> handlers {handler};
|
|
_event_handlers.emplace(type, handlers);
|
|
}
|
|
}
|
|
|
|
bool Window::handle_event(const SDL_Event& event, bool quit) {
|
|
auto it = _event_handlers.find(static_cast<SDL_WindowEventID>(event.window.event));
|
|
if (it != _event_handlers.end()) {
|
|
for (WindowEventHandler handler : it->second) {
|
|
quit = handler(event, quit);
|
|
}
|
|
}
|
|
return quit;
|
|
}
|
|
|
|
int Window::width() const {
|
|
int w, h;
|
|
SDL_GetWindowSize(_w.get(), &w, &h);
|
|
return w;
|
|
}
|
|
|
|
int Window::height() const {
|
|
int w, h;
|
|
SDL_GetWindowSize(_w.get(), &w, &h);
|
|
return h;
|
|
}
|