McRogueFace/src/PyColor.h
John McCardle 95463bdc78 Add Color.__eq__/__ne__ for value comparison, closes #307
Color had __hash__ but no __eq__/__ne__, violating the Python convention
that hashable objects must support equality comparison. Two Color objects
with identical RGBA values would not compare equal.

Now supports comparison with Color objects, tuples, and lists:
  Color(255, 0, 0) == Color(255, 0, 0)  # True
  Color(255, 0, 0) == (255, 0, 0)       # True
  Color(255, 0, 0) != (0, 0, 0)         # True

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 21:18:47 -04:00

85 lines
2.9 KiB
C++

#pragma once
#include "Common.h"
#include "Python.h"
class PyColor;
class UIDrawable; // forward declare for pointer
typedef struct {
PyObject_HEAD
sf::Color data;
} PyColorObject;
class PyColor
{
private:
public:
sf::Color data;
PyColor(sf::Color);
void set(sf::Color);
sf::Color get();
PyObject* pyObject();
static sf::Color fromPy(PyObject*);
static sf::Color fromPy(PyColorObject*);
static PyObject* repr(PyObject*);
static Py_hash_t hash(PyObject*);
static PyObject* richcompare(PyObject*, PyObject*, int);
static int init(PyColorObject*, PyObject*, PyObject*);
static PyObject* pynew(PyTypeObject* type, PyObject* args=NULL, PyObject* kwds=NULL);
static PyObject* get_member(PyObject*, void*);
static int set_member(PyObject*, PyObject*, void*);
// Color helper methods
static PyObject* from_hex(PyObject* cls, PyObject* args);
static PyObject* to_hex(PyColorObject* self, PyObject* Py_UNUSED(ignored));
static PyObject* lerp(PyColorObject* self, PyObject* args);
static PyGetSetDef getsetters[];
static PyMethodDef methods[];
static PyColorObject* from_arg(PyObject*);
};
namespace mcrfpydef {
inline PyTypeObject PyColorType = {
.ob_base = {.ob_base = {.ob_refcnt = 1, .ob_type = NULL}, .ob_size = 0},
.tp_name = "mcrfpy.Color",
.tp_basicsize = sizeof(PyColorObject),
.tp_itemsize = 0,
.tp_repr = PyColor::repr,
.tp_hash = PyColor::hash,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = PyDoc_STR(
"Color(r: int = 0, g: int = 0, b: int = 0, a: int = 255)\n"
"\n"
"RGBA color representation.\n"
"\n"
"Args:\n"
" r: Red component (0-255)\n"
" g: Green component (0-255)\n"
" b: Blue component (0-255)\n"
" a: Alpha component (0-255, default 255 = opaque)\n"
"\n"
"Note:\n"
" When accessing colors from UI elements (e.g., frame.fill_color),\n"
" you receive a COPY of the color. Modifying it doesn't affect the\n"
" original. To change a component:\n"
"\n"
" # This does NOT work:\n"
" frame.fill_color.r = 255 # Modifies a temporary copy\n"
"\n"
" # Do this instead:\n"
" c = frame.fill_color\n"
" c.r = 255\n"
" frame.fill_color = c\n"
"\n"
" # Or use Animation for sub-properties:\n"
" anim = mcrfpy.Animation('fill_color.r', 255, 0.5, 'linear')\n"
" anim.start(frame)\n"
),
.tp_richcompare = PyColor::richcompare,
.tp_methods = PyColor::methods,
.tp_getset = PyColor::getsetters,
.tp_init = (initproc)PyColor::init,
.tp_new = PyColor::pynew,
};
}