Redesign psemek::sdl2 cursor api
This commit is contained in:
parent
13862d8b47
commit
7151fef7a8
2 changed files with 62 additions and 139 deletions
|
|
@ -4,40 +4,31 @@
|
||||||
#include <psemek/geom/point.hpp>
|
#include <psemek/geom/point.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace psemek::sdl2
|
namespace psemek::sdl2
|
||||||
{
|
{
|
||||||
|
|
||||||
enum class cursor_type
|
enum class default_cursor_type
|
||||||
{
|
{
|
||||||
arrow,
|
arrow,
|
||||||
beam,
|
beam,
|
||||||
|
wait,
|
||||||
|
crosshair,
|
||||||
|
waitarrow,
|
||||||
|
sizenwse,
|
||||||
|
sizenesw,
|
||||||
|
sizewe,
|
||||||
|
sizens,
|
||||||
|
sizeall,
|
||||||
|
no,
|
||||||
hand,
|
hand,
|
||||||
size,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cursor;
|
struct cursor;
|
||||||
|
|
||||||
struct cursor_provider
|
std::shared_ptr<cursor> get_default_cursor(default_cursor_type type);
|
||||||
{
|
std::shared_ptr<cursor> make_cursor(gfx::pixmap_rgba const & image, geom::point<int, 2> const & pivot);
|
||||||
virtual cursor const & get(cursor_type type) const = 0;
|
|
||||||
|
|
||||||
virtual ~cursor_provider() {}
|
void set_cursor(cursor const & cursor);
|
||||||
};
|
|
||||||
|
|
||||||
struct image_cursor_description
|
|
||||||
{
|
|
||||||
gfx::pixmap_rgba image;
|
|
||||||
geom::point<int, 2> pivot;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<cursor_provider> system_cursor_provider();
|
|
||||||
std::unique_ptr<cursor_provider> image_cursor_provider(std::function<image_cursor_description(cursor_type)> image_provider);
|
|
||||||
|
|
||||||
std::unique_ptr<cursor_provider> set_cursor_provider(std::unique_ptr<cursor_provider> new_provider);
|
|
||||||
cursor_provider const * get_cursor_provider();
|
|
||||||
|
|
||||||
void set_cursor(cursor_type type);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace psemek::sdl2
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
struct surface_deleter
|
struct sdl_surface_deleter
|
||||||
{
|
{
|
||||||
void operator() (SDL_Surface * s) const
|
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
|
void operator() (SDL_Cursor * c) const
|
||||||
{
|
{
|
||||||
|
|
@ -29,138 +29,70 @@ namespace psemek::sdl2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using surface_ptr = std::unique_ptr<SDL_Surface, surface_deleter>;
|
using sdl_surface_ptr = std::unique_ptr<SDL_Surface, sdl_surface_deleter>;
|
||||||
using cursor_ptr = std::unique_ptr<SDL_Cursor, cursor_deleter>;
|
using sdl_cursor_ptr = std::unique_ptr<SDL_Cursor, sdl_cursor_deleter>;
|
||||||
|
|
||||||
|
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
|
struct cursor
|
||||||
{
|
{
|
||||||
std::unique_ptr<SDL_Cursor, cursor_deleter> cursor;
|
sdl_cursor_ptr cursor_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace
|
std::shared_ptr<cursor> get_default_cursor(default_cursor_type type)
|
||||||
{
|
{
|
||||||
|
sdl_cursor_ptr cursor_ptr{SDL_CreateSystemCursor(to_sdl(type))};
|
||||||
SDL_Cursor * create_system_cursor(SDL_SystemCursor id)
|
if (!cursor_ptr)
|
||||||
{
|
{
|
||||||
auto cursor = SDL_CreateSystemCursor(id);
|
|
||||||
if (!cursor)
|
|
||||||
log::warning() << "Failed to create system cursor: " << SDL_GetError();
|
log::warning() << "Failed to create system cursor: " << SDL_GetError();
|
||||||
return cursor;
|
return nullptr;
|
||||||
|
}
|
||||||
|
return std::make_shared<cursor>(std::move(cursor_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct system_cursor_provider_impl
|
std::shared_ptr<cursor> make_cursor(gfx::pixmap_rgba const & image, geom::point<int, 2> const & pivot)
|
||||||
: cursor_provider
|
|
||||||
{
|
{
|
||||||
system_cursor_provider_impl()
|
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)
|
||||||
{
|
{
|
||||||
arrow_.cursor.reset(create_system_cursor(SDL_SYSTEM_CURSOR_ARROW));
|
log::warning() << "Failed to create cursor SDL surface: " << SDL_GetError();
|
||||||
beam_.cursor.reset(create_system_cursor(SDL_SYSTEM_CURSOR_IBEAM));
|
return nullptr;
|
||||||
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
|
sdl_cursor_ptr cursor_ptr{SDL_CreateColorCursor(surface_ptr.get(), pivot[0], pivot[1])};
|
||||||
|
if (!cursor_ptr)
|
||||||
{
|
{
|
||||||
switch (type)
|
log::warning() << "Failed to create cursor from SDL surface: " << SDL_GetError();
|
||||||
{
|
return nullptr;
|
||||||
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<cursor_type>(type);
|
return std::make_shared<cursor>(std::move(cursor_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void set_cursor(cursor const & cursor)
|
||||||
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)};
|
SDL_SetCursor(cursor.cursor_ptr.get());
|
||||||
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_cursor_description(cursor_type)> 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<cursor_type>(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
cursor arrow_;
|
|
||||||
cursor beam_;
|
|
||||||
cursor hand_;
|
|
||||||
cursor size_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<cursor_provider> system_cursor_provider()
|
|
||||||
{
|
|
||||||
return std::make_unique<system_cursor_provider_impl>();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<cursor_provider> image_cursor_provider(std::function<image_cursor_description(cursor_type)> image_provider)
|
|
||||||
{
|
|
||||||
return std::make_unique<image_cursor_provider_impl>(std::move(image_provider));
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::unique_ptr<cursor_provider> current_provider;
|
|
||||||
|
|
||||||
std::unique_ptr<cursor_provider> set_cursor_provider(std::unique_ptr<cursor_provider> new_provider)
|
|
||||||
{
|
|
||||||
std::swap(current_provider, new_provider);
|
|
||||||
return new_provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor_provider const * get_cursor_provider()
|
|
||||||
{
|
|
||||||
static std::unique_ptr<cursor_provider> 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue