bwidgets/inc/basic_widgets/core/type/color.hpp

137 lines
4.2 KiB
C++

#ifndef BWIDGETS_COLOR_HPP
#define BWIDGETS_COLOR_HPP
#include <cstdint>
#include <functional>
#include <SDL2/SDL_assert.h>
#include <SDL2/SDL_pixels.h>
#include <basic_widgets/core/type/concepts.hpp>
namespace bwidgets
{
class Color final
{
public:
[[nodiscard]] inline auto& operator()()
{
return sdl_type;
}
[[nodiscard]] inline const auto& operator()() const
{
return sdl_type;
}
private:
bool _operate_on_alpha;
bool _operate_on_colors;
template<Numeric N>
inline auto _operate(const N& operand,
const std::function<N(const N&, const N&)>& operator_) const
{
Color c(sdl_type, _operate_on_alpha, _operate_on_colors);
if (_operate_on_alpha) {
auto a = std::round(operator_(c().a, operand));
SDL_assert_release(a == (uint8_t)a); // NOLINT
c().a = (uint8_t)a;
}
if (_operate_on_colors) {
auto r = std::round(operator_(c().r, operand));
auto g = std::round(operator_(c().g, operand));
auto b = std::round(operator_(c().b, operand));
// NOLINTNEXTLINE
SDL_assert_release(r == (uint8_t)r && g == (uint8_t)g
&& b == (uint8_t)b);
c().r = (uint8_t)r;
c().g = (uint8_t)g;
c().b = (uint8_t)b;
}
return c;
}
public:
SDL_Color sdl_type;
inline Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a,
bool op_on_alpha = false, bool op_on_colors = true) noexcept
: _operate_on_alpha(op_on_alpha),
_operate_on_colors(op_on_colors),
sdl_type({r, g, b, a})
{}
inline Color(const SDL_Color& c = {}, bool op_on_alpha = false,
bool op_on_colors = true) noexcept
: _operate_on_alpha(op_on_alpha), _operate_on_colors(op_on_colors), sdl_type(c)
{}
inline Color(const Color&) noexcept = default;
[[nodiscard]] inline auto alpha() const -> Color
{
return {sdl_type, _operate_on_colors, true};
}
[[nodiscard]] inline auto colors() const -> Color
{
return {sdl_type, true, _operate_on_alpha};
}
template<Numeric N>
[[nodiscard]] inline auto operator+(const N& operand) const
{
return _operate(operand, [](const N& a, const N& b) { return a + b; });
}
template<Numeric N>
[[nodiscard]] inline auto operator-(const N& operand) const
{
return _operate(operand, [](const N& a, const N& b) { return a - b; });
}
template<Numeric N>
[[nodiscard]] inline auto operator*(const N& operand) const
{
return _operate(operand, [](const N& a, const N& b) { return a * b; });
}
template<Numeric N>
[[nodiscard]] inline auto operator/(const N& operand) const
{
SDL_assert(operand != 0); // NOLINT
return _operate<N>(operand, [](const N& a, const N& b) { return a / b; });
}
inline auto& operator=(const Color& c)
{
if (this != &c) {
sdl_type = c.sdl_type;
}
return *this;
}
inline auto& operator=(const SDL_Color& c)
{
sdl_type = c;
return *this;
}
[[nodiscard]] inline auto operator==(const Color& other) const
{
return (_operate_on_colors && sdl_type.r == other().r
&& sdl_type.g == other().g && sdl_type.b == other().b)
|| (_operate_on_alpha && sdl_type.a == other().a);
}
[[nodiscard]] inline auto operator!=(const Color& other) const
{
return (sdl_type.r != other().r || sdl_type.g != other().g
|| sdl_type.b != other().b)
&& ((_operate_on_alpha && sdl_type.a != other().a)
|| !_operate_on_alpha);
}
};
}
#endif