// // Window.cpp // gui // // Created by Bob Polis at 2020-10-14 // Copyright (c) 2020 SwiftCoder. All rights reserved. // #include #include #include #include "Window.hpp" #include "Image.hpp" using namespace sc::gui; std::vector Window::_windows; std::map> 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 {handle_global_event(event)}; Window* w {from_sdl(event.window.windowID)}; if (w) { return w->handle_event(event, quit); } return quit; } bool Window::handle_global_event(const SDL_Event& event) { bool quit {false}; auto iter = _global_event_handlers.find(static_cast(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 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, 800, 450, 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(dm.w) / dm.h}; double image_ratio {static_cast(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(round(image_ratio * h)); } else { // screen relatively less wide than image w = dm.w - safety; h = static_cast(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 handlers {handler}; _event_handlers.emplace(type, handlers); } } bool Window::handle_event(const SDL_Event& event, bool quit) { auto it = _event_handlers.find(static_cast(event.window.event)); if (it != _event_handlers.end()) { for (WindowEventHandler handler : it->second) { quit = handler(event, quit); } } return quit; }