Files
Gleb Mazovetskiy f2d730a52f Delay hardware cursor reinit until it is visible
We previously reinitialized the hardware cursor during fade in even if
it was not visible (e.g. fading into the credits screen).
2023-05-20 15:33:41 +01:00

177 lines
3.3 KiB
C++

/**
* @file hwcursor.hpp
*
* Hardware cursor (SDL2 only).
*/
#pragma once
#include <cstdint>
#include <SDL_version.h>
#include "options.h"
#include "utils/log.hpp"
// Set this to 1 to log the hardware cursor state changes.
#define LOG_HWCURSOR 0
namespace devilution {
// Whether the hardware cursor is enabled in settings.
inline bool IsHardwareCursorEnabled()
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
return *sgOptions.Graphics.hardwareCursor && HardwareCursorSupported();
#else
return false;
#endif
}
enum class CursorType : uint8_t {
Unknown,
UserInterface,
Game,
};
class CursorInfo {
public:
CursorInfo() = default;
static CursorInfo UserInterfaceCursor()
{
return CursorInfo { CursorType::UserInterface };
}
static CursorInfo GameCursor(int gameSpriteId)
{
return CursorInfo { CursorType::Game, gameSpriteId };
}
static CursorInfo UnknownCursor()
{
return CursorInfo { CursorType::Unknown };
}
[[nodiscard]] CursorType type() const
{
return type_;
}
[[nodiscard]] int id() const
{
return id_;
}
[[nodiscard]] bool Enabled() const
{
return enabled_;
}
void SetEnabled(bool value)
{
#if LOG_HWCURSOR
if (enabled_ != value) {
Log("hwcursor: SetEnabled {}", value);
}
#endif
enabled_ = value;
}
[[nodiscard]] bool needsReinitialization()
{
return needs_reinitialization_;
}
void setNeedsReinitialization(bool value)
{
#if LOG_HWCURSOR
if (needs_reinitialization_ != value) {
Log("hwcursor: setNeedsReinitialization {}", value);
}
#endif
needs_reinitialization_ = value;
}
bool operator==(const CursorInfo &other) const
{
return type_ == other.type_ && (type_ != CursorType::Game || id_ == other.id_);
}
bool operator!=(const CursorInfo &other) const
{
return !(*this == other);
}
private:
explicit CursorInfo(CursorType type, int id = 0)
: type_(type)
, id_(id)
, enabled_(false)
{
}
CursorType type_ = CursorType::Unknown;
// ID for CursorType::Game
int id_;
bool enabled_ = false;
bool needs_reinitialization_ = false;
};
CursorInfo &GetCurrentCursorInfo();
// Whether the current cursor is a hardware cursor.
inline bool IsHardwareCursor()
{
return GetCurrentCursorInfo().Enabled();
}
void SetHardwareCursor(CursorInfo cursorInfo);
inline void DoReinitializeHardwareCursor()
{
#if LOG_HWCURSOR
Log("hwcursor: DoReinitializeHardwareCursor");
#endif
SetHardwareCursor(GetCurrentCursorInfo());
}
inline bool IsHardwareCursorVisible()
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE;
#else
return false;
#endif
}
inline void SetHardwareCursorVisible(bool visible)
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (IsHardwareCursorVisible() == visible)
return;
if (visible && GetCurrentCursorInfo().needsReinitialization()) {
DoReinitializeHardwareCursor();
}
#if LOG_HWCURSOR
Log("hwcursor: SetHardwareCursorVisible {}", visible);
#endif
if (SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE) < 0) {
LogError("{}", SDL_GetError());
SDL_ClearError();
}
#endif
}
inline void ReinitializeHardwareCursor()
{
if (IsHardwareCursorVisible()) {
DoReinitializeHardwareCursor();
} else {
GetCurrentCursorInfo().setNeedsReinitialization(true);
}
}
} // namespace devilution