diff --git a/libs/sdl2/include/psemek/sdl2/cursor.hpp b/libs/sdl2/include/psemek/sdl2/cursor.hpp index 127ee3c8..7f08ddb9 100644 --- a/libs/sdl2/include/psemek/sdl2/cursor.hpp +++ b/libs/sdl2/include/psemek/sdl2/cursor.hpp @@ -4,40 +4,31 @@ #include #include -#include namespace psemek::sdl2 { - enum class cursor_type + enum class default_cursor_type { arrow, beam, + wait, + crosshair, + waitarrow, + sizenwse, + sizenesw, + sizewe, + sizens, + sizeall, + no, hand, - size, }; struct cursor; - struct cursor_provider - { - virtual cursor const & get(cursor_type type) const = 0; + std::shared_ptr get_default_cursor(default_cursor_type type); + std::shared_ptr make_cursor(gfx::pixmap_rgba const & image, geom::point const & pivot); - virtual ~cursor_provider() {} - }; - - struct image_cursor_description - { - gfx::pixmap_rgba image; - geom::point pivot; - }; - - std::unique_ptr system_cursor_provider(); - std::unique_ptr image_cursor_provider(std::function image_provider); - - std::unique_ptr set_cursor_provider(std::unique_ptr new_provider); - cursor_provider const * get_cursor_provider(); - - void set_cursor(cursor_type type); + void set_cursor(cursor const & cursor); } diff --git a/libs/sdl2/source/cursor.cpp b/libs/sdl2/source/cursor.cpp index 2368a2f2..65e3accd 100644 --- a/libs/sdl2/source/cursor.cpp +++ b/libs/sdl2/source/cursor.cpp @@ -13,7 +13,7 @@ namespace psemek::sdl2 namespace { - struct surface_deleter + struct sdl_surface_deleter { void operator() (SDL_Surface * s) const { @@ -21,7 +21,7 @@ namespace psemek::sdl2 } }; - struct cursor_deleter + struct sdl_cursor_deleter { void operator() (SDL_Cursor * c) const { @@ -29,138 +29,70 @@ namespace psemek::sdl2 } }; - using surface_ptr = std::unique_ptr; - using cursor_ptr = std::unique_ptr; + using sdl_surface_ptr = std::unique_ptr; + using sdl_cursor_ptr = std::unique_ptr; + + SDL_SystemCursor to_sdl(default_cursor_type type) + { + switch (type) + { + case default_cursor_type::arrow: return SDL_SYSTEM_CURSOR_ARROW; + case default_cursor_type::beam: return SDL_SYSTEM_CURSOR_IBEAM; + case default_cursor_type::wait: return SDL_SYSTEM_CURSOR_WAIT; + case default_cursor_type::crosshair: return SDL_SYSTEM_CURSOR_CROSSHAIR; + case default_cursor_type::waitarrow: return SDL_SYSTEM_CURSOR_WAITARROW; + case default_cursor_type::sizenwse: return SDL_SYSTEM_CURSOR_SIZENWSE; + case default_cursor_type::sizenesw: return SDL_SYSTEM_CURSOR_SIZENESW; + case default_cursor_type::sizewe: return SDL_SYSTEM_CURSOR_SIZEWE; + case default_cursor_type::sizens: return SDL_SYSTEM_CURSOR_SIZENS; + case default_cursor_type::sizeall: return SDL_SYSTEM_CURSOR_SIZEALL; + case default_cursor_type::no: return SDL_SYSTEM_CURSOR_NO; + case default_cursor_type::hand: return SDL_SYSTEM_CURSOR_HAND; + } + + return SDL_SYSTEM_CURSOR_ARROW; + } } struct cursor { - std::unique_ptr cursor; + sdl_cursor_ptr cursor_ptr; }; - namespace + std::shared_ptr get_default_cursor(default_cursor_type type) { - - SDL_Cursor * create_system_cursor(SDL_SystemCursor id) + sdl_cursor_ptr cursor_ptr{SDL_CreateSystemCursor(to_sdl(type))}; + if (!cursor_ptr) { - auto cursor = SDL_CreateSystemCursor(id); - if (!cursor) - log::warning() << "Failed to create system cursor: " << SDL_GetError(); - return cursor; + log::warning() << "Failed to create system cursor: " << SDL_GetError(); + return nullptr; + } + return std::make_shared(std::move(cursor_ptr)); + } + + std::shared_ptr make_cursor(gfx::pixmap_rgba const & image, geom::point const & pivot) + { + sdl_surface_ptr surface_ptr{SDL_CreateRGBSurfaceFrom((void *)image.data(), image.width(), image.height(), 32, 4 * image.width(), 0x000000ffu, 0x0000ff00u, 0x00ff0000u, 0xff000000u)}; + if (!surface_ptr) + { + log::warning() << "Failed to create cursor SDL surface: " << SDL_GetError(); + return nullptr; } - struct system_cursor_provider_impl - : cursor_provider + sdl_cursor_ptr cursor_ptr{SDL_CreateColorCursor(surface_ptr.get(), pivot[0], pivot[1])}; + if (!cursor_ptr) { - system_cursor_provider_impl() - { - arrow_.cursor.reset(create_system_cursor(SDL_SYSTEM_CURSOR_ARROW)); - beam_.cursor.reset(create_system_cursor(SDL_SYSTEM_CURSOR_IBEAM)); - hand_.cursor.reset(create_system_cursor(SDL_SYSTEM_CURSOR_HAND)); - size_.cursor.reset(create_system_cursor(SDL_SYSTEM_CURSOR_SIZEALL)); - } - - cursor const & get(cursor_type type) const override - { - switch (type) - { - case cursor_type::arrow: return arrow_; - case cursor_type::beam: return beam_; - case cursor_type::hand: return hand_; - case cursor_type::size: return size_; - } - - throw util::unknown_enum_value_exception(type); - } - - private: - cursor arrow_; - cursor beam_; - cursor hand_; - cursor size_; - }; - - cursor_ptr create_image_cursor(image_cursor_description desc) - { - surface_ptr surface{SDL_CreateRGBSurfaceFrom(desc.image.data(), desc.image.width(), desc.image.height(), 32, 4 * desc.image.width(), 0x000000ffu, 0x0000ff00u, 0x00ff0000u, 0xff000000u)}; - if (!surface) - fail("failed to create cursor surface: "); - - cursor_ptr cursor{SDL_CreateColorCursor(surface.get(), desc.pivot[0], desc.pivot[1])}; - if (!cursor) - fail("failed to create cursor: "); - - return cursor; + log::warning() << "Failed to create cursor from SDL surface: " << SDL_GetError(); + return nullptr; } - struct image_cursor_provider_impl - : cursor_provider - { - image_cursor_provider_impl(std::function image_provider) - { - arrow_.cursor = create_image_cursor(image_provider(cursor_type::arrow)); - beam_.cursor = create_image_cursor(image_provider(cursor_type::beam)); - hand_.cursor = create_image_cursor(image_provider(cursor_type::hand)); - size_.cursor = create_image_cursor(image_provider(cursor_type::size)); - } - - cursor const & get(cursor_type type) const override - { - switch (type) - { - case cursor_type::arrow: return arrow_; - case cursor_type::beam: return beam_; - case cursor_type::hand: return hand_; - case cursor_type::size: return size_; - } - - throw util::unknown_enum_value_exception(type); - } - - private: - cursor arrow_; - cursor beam_; - cursor hand_; - cursor size_; - }; - + return std::make_shared(std::move(cursor_ptr)); } - std::unique_ptr system_cursor_provider() + void set_cursor(cursor const & cursor) { - return std::make_unique(); - } - - std::unique_ptr image_cursor_provider(std::function image_provider) - { - return std::make_unique(std::move(image_provider)); - } - - static std::unique_ptr current_provider; - - std::unique_ptr set_cursor_provider(std::unique_ptr new_provider) - { - std::swap(current_provider, new_provider); - return new_provider; - } - - cursor_provider const * get_cursor_provider() - { - static std::unique_ptr fallback; - - if (current_provider) - return current_provider.get(); - - if (!fallback) - fallback = system_cursor_provider(); - - return fallback.get(); - } - - void set_cursor(cursor_type type) - { - SDL_SetCursor(get_cursor_provider()->get(type).cursor.get()); + SDL_SetCursor(cursor.cursor_ptr.get()); }