From 88e48f24546fe075d356816bae34a90381cd4296 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 22 May 2022 20:24:57 +0300 Subject: [PATCH] Support image-based cursors --- libs/sdl2/CMakeLists.txt | 2 +- libs/sdl2/include/psemek/sdl2/cursor.hpp | 11 +++++ libs/sdl2/source/cursor.cpp | 56 ++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/libs/sdl2/CMakeLists.txt b/libs/sdl2/CMakeLists.txt index 1db2f5aa..53e0c832 100644 --- a/libs/sdl2/CMakeLists.txt +++ b/libs/sdl2/CMakeLists.txt @@ -5,4 +5,4 @@ file(GLOB_RECURSE PSEMEK_SDL2_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "so psemek_add_library(psemek-sdl2 ${PSEMEK_SDL2_HEADERS} ${PSEMEK_SDL2_SOURCES}) target_include_directories(psemek-sdl2 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(psemek-sdl2 PUBLIC psemek-log psemek-util SDL2) +target_link_libraries(psemek-sdl2 PUBLIC psemek-log psemek-util psemek-gfx SDL2) diff --git a/libs/sdl2/include/psemek/sdl2/cursor.hpp b/libs/sdl2/include/psemek/sdl2/cursor.hpp index 13e50c75..48ee8e15 100644 --- a/libs/sdl2/include/psemek/sdl2/cursor.hpp +++ b/libs/sdl2/include/psemek/sdl2/cursor.hpp @@ -1,6 +1,10 @@ #pragma once +#include +#include + #include +#include namespace psemek::sdl2 { @@ -21,7 +25,14 @@ namespace psemek::sdl2 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(); diff --git a/libs/sdl2/source/cursor.cpp b/libs/sdl2/source/cursor.cpp index 2e4e16ca..20457695 100644 --- a/libs/sdl2/source/cursor.cpp +++ b/libs/sdl2/source/cursor.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,6 +13,14 @@ namespace psemek::sdl2 namespace { + struct surface_deleter + { + void operator() (SDL_Surface * s) const + { + SDL_FreeSurface(s); + } + }; + struct cursor_deleter { void operator() (SDL_Cursor * c) const @@ -20,6 +29,7 @@ namespace psemek::sdl2 } }; + using surface_ptr = std::unique_ptr; using cursor_ptr = std::unique_ptr; } @@ -68,6 +78,47 @@ namespace psemek::sdl2 cursor hand_; }; + 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; + } + + 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)); + } + + 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_; + } + + throw util::unknown_enum_value_exception(type); + } + + private: + cursor arrow_; + cursor beam_; + cursor hand_; + }; + } std::unique_ptr system_cursor_provider() @@ -75,6 +126,11 @@ namespace psemek::sdl2 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)