1/* -*- Mode: C; c-basic-offset: 4 -*- 2 * pygtk- Python bindings for the GTK toolkit. 3 * Copyright (C) 1998-2003 James Henstridge 4 * 5 * gdkcolor.override: gtk.gdk.Color and gtk.gdk.ColorMap overrides 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 20 * USA 21 */ 22%% 23ignore 24 gdk_color_copy gdk_color_free 25 gdk_color_hash gdk_color_equal 26%% 27override gdk_color_new kwargs 28static int 29_wrap_gdk_color_new(PyGBoxed *self, 30 PyObject *args, 31 PyObject *kwargs) 32{ 33 static char *kwlist1[] = {"red", "green", "blue", "pixel", NULL }; 34 static char *kwlist2[] = { "spec", NULL }; 35 PyObject *red = Py_None, *green = Py_None, *blue = Py_None; 36 const char *spec = NULL; 37 GdkColor colour; 38 39 /* Note: this constructor has become quite complicated, because it 40 * is heavily overloaded. Additionally, we try to optimize a 41 * little. */ 42 43 if (PyArg_ParseTupleAndKeywords(args, kwargs, "|s:gdk.Color", kwlist2, 44 &spec)) { 45 if (!spec) 46 memset(&colour, 0, sizeof(colour)); 47 else if (!gdk_color_parse(spec, &colour)) { 48 PyErr_SetString(PyExc_ValueError, 49 "unable to parse colour specification"); 50 return -1; 51 } 52 53 goto success; 54 } 55 56 PyErr_Clear(); 57 58 if (PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOk:gdk.Color", kwlist1, 59 &red, &green, &blue, &colour.pixel)) { 60 /* We don't allow mixing floats and non-floats as that is too 61 * error-prone. All non-floats are deemed integers in case 62 * they have __int__() method. */ 63 int have_floats = 0; 64 int have_nonfloats = 0; 65 66 if (red == Py_None) 67 colour.red = 0; 68 else { 69 if (PyFloat_Check(red)) { 70 have_floats = 1; 71 colour.red = MIN(MAX(0.0, PyFloat_AsDouble(red)), 1.0) * 65535.0; 72 } 73 else { 74 have_nonfloats = 1; 75 colour.red = PyInt_AsLong(red); 76 } 77 } 78 79 if (PyErr_Occurred()) 80 return -1; 81 82 if (green == Py_None) 83 colour.green = 0; 84 else { 85 if (PyFloat_Check(green)) { 86 if (have_nonfloats) 87 goto mixed_types_error; 88 have_floats = 1; 89 colour.green = MIN(MAX(0.0, PyFloat_AsDouble(green)), 1.0) * 65535.0; 90 } 91 else { 92 if (have_floats) 93 goto mixed_types_error; 94 have_nonfloats = 1; 95 colour.green = PyInt_AsLong(green); 96 } 97 } 98 99 if (PyErr_Occurred()) 100 return -1; 101 102 if (blue == Py_None) 103 colour.blue = 0; 104 else { 105 if (PyFloat_Check(blue)) { 106 if (have_nonfloats) 107 goto mixed_types_error; 108 colour.blue = MIN(MAX(0.0, PyFloat_AsDouble(blue)), 1.0) * 65535.0; 109 } 110 else { 111 if (have_floats) 112 goto mixed_types_error; 113 colour.blue = PyInt_AsLong(blue); 114 } 115 } 116 117 if (PyErr_Occurred()) 118 return -1; 119 120 goto success; 121 122 mixed_types_error: 123 PyErr_SetString(PyExc_TypeError, "arguments must either be all integers or all floats"); 124 return -1; 125 } 126 127 PyErr_Clear(); 128 PyErr_SetString(PyExc_TypeError, "Usage:\n" 129 " gtk.gdk.Color(red, green, blue, pixel) [all are optional]\n" 130 " gtk.gdk.Color(spec) [see gtk.gdk.color_parse()]"); 131 return -1; 132 133 success: 134 self->boxed = g_boxed_copy(GDK_TYPE_COLOR, &colour); 135 self->free_on_dealloc = TRUE; 136 self->gtype = GDK_TYPE_COLOR; 137 138 return 0; 139} 140 141%% 142define color_from_hsv kwargs 143static PyObject * 144_wrap_color_from_hsv (PyObject *ignored, PyObject *args, PyObject*kwargs) 145{ 146 static char *kwlist[] = { "hue", "saturation", "value", NULL }; 147 gdouble hue, saturation, value; 148 gdouble red, green, blue; 149 GdkColor color; 150 151 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ddd:gtk.gdk.color_from_hsv", kwlist, 152 &hue, &saturation, &value)) 153 return NULL; 154 155 /* See documentation of the class for rationale. */ 156 157 hue -= floor(hue); 158 159 if (saturation > 1.0) 160 saturation = 1.0; 161 else if (saturation < 0.0) 162 saturation = 0.0; 163 164 if (value > 1.0) 165 value = 1.0; 166 else if (value < 0.0) 167 value = 0.0; 168 169 gtk_hsv_to_rgb(hue, saturation, value, 170 &red, &green, &blue); 171 172 color.red = red * 65535.0; 173 color.green = green * 65535.0; 174 color.blue = blue * 65535.0; 175 176 return pyg_boxed_new(GDK_TYPE_COLOR, &color, TRUE, TRUE); 177} 178 179%% 180override-attr GdkColor.red 181static int 182_wrap_gdk_color__set_red(PyObject *self, PyObject *value, void *closure) 183{ 184 long red = PyInt_AsLong(value); 185 if (red == -1 && PyErr_Occurred()) 186 return -1; 187 else { 188 pyg_boxed_get(self, GdkColor)->red = red; 189 return 0; 190 } 191} 192%% 193override-attr GdkColor.blue 194static int 195_wrap_gdk_color__set_blue(PyObject *self, PyObject *value, void *closure) 196{ 197 long blue = PyInt_AsLong(value); 198 if (blue == -1 && PyErr_Occurred()) 199 return -1; 200 else { 201 pyg_boxed_get(self, GdkColor)->blue = blue; 202 return 0; 203 } 204} 205%% 206override-attr GdkColor.green 207static int 208_wrap_gdk_color__set_green(PyObject *self, PyObject *value, void *closure) 209{ 210 long green = PyInt_AsLong(value); 211 if (green == -1 && PyErr_Occurred()) 212 return -1; 213 else { 214 pyg_boxed_get(self, GdkColor)->green = green; 215 return 0; 216 } 217} 218%% 219override-attr GdkColor.pixel 220static int 221_wrap_gdk_color__set_pixel(PyObject *self, PyObject *value, void *closure) 222{ 223 long pixel = PyInt_AsLong(value); 224 if (pixel == -1 && PyErr_Occurred()) 225 return -1; 226 else { 227 pyg_boxed_get(self, GdkColor)->pixel = pixel; 228 return 0; 229 } 230} 231%% 232override-attr GdkColor.red_float 233 234static PyObject * 235_wrap_gdk_color__get_red_float(PyObject *self, void *closure) 236{ 237 return PyFloat_FromDouble(pyg_boxed_get(self, GdkColor)->red / 65535.0); 238} 239 240static int 241_wrap_gdk_color__set_red_float(PyObject *self, PyObject *value, void *closure) 242{ 243 double red = PyFloat_AsDouble(value); 244 if (red == -1 && PyErr_Occurred()) 245 return -1; 246 else { 247 pyg_boxed_get(self, GdkColor)->red = MIN(MAX(0.0, red), 1.0) * 65535.0; 248 return 0; 249 } 250} 251%% 252override-attr GdkColor.green_float 253 254static PyObject * 255_wrap_gdk_color__get_green_float(PyObject *self, void *closure) 256{ 257 return PyFloat_FromDouble(pyg_boxed_get(self, GdkColor)->green / 65535.0); 258} 259 260static int 261_wrap_gdk_color__set_green_float(PyObject *self, PyObject *value, void *closure) 262{ 263 double green = PyFloat_AsDouble(value); 264 if (green == -1 && PyErr_Occurred()) 265 return -1; 266 else { 267 pyg_boxed_get(self, GdkColor)->green = MIN(MAX(0.0, green), 1.0) * 65535.0; 268 return 0; 269 } 270} 271%% 272override-attr GdkColor.blue_float 273 274static PyObject * 275_wrap_gdk_color__get_blue_float(PyObject *self, void *closure) 276{ 277 return PyFloat_FromDouble(pyg_boxed_get(self, GdkColor)->blue / 65535.0); 278} 279 280static int 281_wrap_gdk_color__set_blue_float(PyObject *self, PyObject *value, void *closure) 282{ 283 double blue = PyFloat_AsDouble(value); 284 if (blue == -1 && PyErr_Occurred()) 285 return -1; 286 else { 287 pyg_boxed_get(self, GdkColor)->blue = MIN(MAX(0.0, blue), 1.0) * 65535.0; 288 return 0; 289 } 290} 291%% 292override-attr GdkColor.hue 293 294static PyObject * 295_wrap_gdk_color__get_hue(PyObject *self, void *closure) 296{ 297 GdkColor *color = pyg_boxed_get(self, GdkColor); 298 gdouble red = color->red / 65535.0; 299 gdouble green = color->green / 65535.0; 300 gdouble blue = color->blue / 65535.0; 301 gdouble hue; 302 303 gtk_rgb_to_hsv(red, green, blue, &hue, NULL, NULL); 304 return PyFloat_FromDouble(hue); 305} 306%% 307override-attr GdkColor.saturation 308 309static PyObject * 310_wrap_gdk_color__get_saturation(PyObject *self, void *closure) 311{ 312 GdkColor *color = pyg_boxed_get(self, GdkColor); 313 gdouble red = color->red / 65535.0; 314 gdouble green = color->green / 65535.0; 315 gdouble blue = color->blue / 65535.0; 316 gdouble saturation; 317 318 gtk_rgb_to_hsv(red, green, blue, NULL, &saturation, NULL); 319 return PyFloat_FromDouble(saturation); 320} 321%% 322override-attr GdkColor.value 323 324static PyObject * 325_wrap_gdk_color__get_value(PyObject *self, void *closure) 326{ 327 GdkColor *color = pyg_boxed_get(self, GdkColor); 328 gdouble red = color->red / 65535.0; 329 gdouble green = color->green / 65535.0; 330 gdouble blue = color->blue / 65535.0; 331 gdouble value; 332 333 gtk_rgb_to_hsv(red, green, blue, NULL, NULL, &value); 334 return PyFloat_FromDouble(value); 335} 336%% 337override gdk_color_parse kwargs 338static PyObject * 339_wrap_gdk_color_parse(PyObject *self, PyObject *args, PyObject *kwargs) 340{ 341 static char *kwlist[] = { "spec", NULL }; 342 const char *spec; 343 GdkColor colour = { 0, }; 344 345 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:color_parse", kwlist, 346 &spec)) 347 return NULL; 348 349 if (!gdk_color_parse(spec, &colour)) { 350 PyErr_SetString(PyExc_ValueError, 351 "unable to parse colour specification"); 352 return NULL; 353 } 354 355 /* pyg_boxed_new handles NULL checking */ 356 return pyg_boxed_new (GDK_TYPE_COLOR, &colour, TRUE, TRUE); 357} 358%% 359override gdk_colormap_alloc_color kwargs 360static PyObject * 361_wrap_gdk_colormap_alloc_color(PyGObject *self, PyObject *args, 362 PyObject *kwargs) 363{ 364 static char *kwlist1[] = { "red", "green", "blue", "writeable", "best_match", NULL }; 365 static char *kwlist2[] = { "spec", "writeable", "best_match", NULL }; 366 static char *kwlist3[] = { "color", "writeable", "best_match", NULL }; 367 GdkColor colour = { 0, 0, 0, 0 }; 368 gboolean writeable = FALSE; 369 gboolean best_match = TRUE; 370 371 if (!PyArg_ParseTupleAndKeywords(args, kwargs, 372 "HHH|ii:GdkColormap.alloc_color", kwlist1, 373 &colour.red, &colour.green, &colour.blue, 374 &writeable, &best_match)) { 375 376 PyObject *pycolour; 377 378 PyErr_Clear(); 379 if (!PyArg_ParseTupleAndKeywords(args, kwargs, 380 "O|ii:GdkColormap.alloc_color", 381 kwlist3, &pycolour, 382 &writeable, &best_match)) { 383 return NULL; 384 } 385 386 if (!pyg_boxed_check(pycolour, GDK_TYPE_COLOR)) { 387 gchar *color_name; 388 389 PyErr_Clear(); 390 if (!PyArg_ParseTupleAndKeywords(args, kwargs, 391 "s|ii:GdkColormap.alloc_color", 392 kwlist2, &color_name, &writeable, 393 &best_match)) { 394 return NULL; 395 } 396 397 if (!gdk_color_parse(color_name, &colour)) { 398 PyErr_SetString(PyExc_ValueError, 399 "unable to parse colour specification"); 400 return NULL; 401 } 402 } else { 403 colour = *pyg_boxed_get(pycolour, GdkColor); 404 } 405 } 406 407 if (!gdk_colormap_alloc_color(GDK_COLORMAP(self->obj), 408 &colour, writeable, best_match)) { 409 PyErr_SetString(PyExc_RuntimeError, "couldn't allocate colour"); 410 return NULL; 411 } 412 return pyg_boxed_new(GDK_TYPE_COLOR, &colour, TRUE, TRUE); 413} 414%% 415override gdk_color_alloc kwargs 416static PyObject * 417_wrap_gdk_color_alloc(PyGObject *self, PyObject *args, PyObject *kwargs) 418{ 419 if (!PyErr_Warn(PyExc_DeprecationWarning, "use GdkColormap.alloc_color")<0) 420 return NULL; 421 return _wrap_gdk_colormap_alloc_color(self, args, kwargs); 422} 423%% 424override-slot GdkColor.tp_richcompare 425static PyObject * 426_wrap_gdk_color_tp_richcompare(PyObject *self, PyObject *other, int op) 427{ 428 PyObject *result; 429 430 if (PyObject_TypeCheck(self, &PyGdkColor_Type) 431 && PyObject_TypeCheck(other, &PyGdkColor_Type)) { 432 GdkColor *color1 = pyg_boxed_get(self, GdkColor); 433 GdkColor *color2 = pyg_boxed_get(other, GdkColor); 434 435 switch (op) { 436 case Py_EQ: 437 result = (gdk_color_equal(color1, color2) 438 ? Py_True : Py_False); 439 break; 440 case Py_NE: 441 result = (!gdk_color_equal(color1, color2) 442 ? Py_True : Py_False); 443 break; 444 default: 445 result = Py_NotImplemented; 446 } 447 } 448 else 449 result = Py_NotImplemented; 450 451 Py_INCREF(result); 452 return result; 453} 454%% 455override-slot GdkColor.tp_repr 456static int 457pygdk_color_to_string_smart(char *buffer, int length, GdkColor *color) 458{ 459 /* We use g_snprintf() because PyString_FromFormat() doesn't support %0Nx-like formats 460 * (i.e. with leading zeros). 461 * 462 * Note that numbers here are used so that there is no off-by-one errors in 463 * 'eval(repr(color))', i.e. so that 'eval(repr(color)) == color'. See 464 * pango_color_parse() for justification of these numbers. Three-nibble color 465 * components are deemed unimportant. 466 */ 467 if (color->red % 0x1111 == 0 && color->green % 0x1111 == 0 && color->blue % 0x1111 == 0) { 468 return g_snprintf(buffer, length, "#%01x%01x%01x", 469 color->red / 0x1111, color->green / 0x1111, color->blue / 0x1111); 470 } 471 else if (color->red % 0x0101 == 0 && color->green % 0x0101 == 0 && color->blue % 0x0101 == 0) { 472 return g_snprintf(buffer, length, "#%02x%02x%02x", 473 color->red / 0x0101, color->green / 0x0101, color->blue / 0x0101); 474 } 475 else { 476 return g_snprintf(buffer, length, "#%04x%04x%04x", 477 color->red, color->green, color->blue); 478 } 479} 480static PyObject * 481_wrap_gdk_color_tp_repr(PyGBoxed *self) 482{ 483 static char buffer[0x40]; 484 int length = 0; 485 486 length += g_snprintf(buffer + length, sizeof buffer - length, "%s('", self->ob_type->tp_name); 487 length += pygdk_color_to_string_smart(buffer + length, sizeof buffer - length, 488 pyg_boxed_get(self, GdkColor)); 489 length += g_snprintf(buffer + length, sizeof buffer - length, "')"); 490 491 return PyString_FromStringAndSize(buffer, length); 492} 493%% 494override-slot GdkColor.tp_str 495static PyObject * 496_wrap_gdk_color_tp_str(PyGBoxed *self) 497{ 498 /* gtk.gdk.Color has a meaningful informal representation, so we define both __repr__ 499 * and __str__, unlike for most other types. 500 */ 501 static char buffer[1 + 4*3 + 1]; /* # + at most 4 digits per component + \0 */ 502 int length = pygdk_color_to_string_smart(buffer, sizeof buffer, pyg_boxed_get(self, GdkColor)); 503 504 return PyString_FromStringAndSize(buffer, length); 505} 506%% 507override gdk_colormap_query_color kwargs 508static PyObject * 509_wrap_gdk_colormap_query_color(PyGObject *self, PyObject *args, 510 PyObject *kwargs) 511{ 512 static char *kwlist[] = { "pixel", NULL }; 513 GdkColor colour = { 0, 0, 0, 0 }; 514 PyObject *py_pixel; 515 gulong pixel; 516 517 if (!PyArg_ParseTupleAndKeywords(args, kwargs, 518 "O:GdkColormap.query_color", kwlist, 519 &py_pixel)) 520 return NULL; 521 522 if (PyLong_Check(py_pixel)) { 523 pixel = PyLong_AsUnsignedLong(py_pixel); 524 if (PyErr_Occurred()) 525 return NULL; 526 } else if (PyInt_Check(py_pixel)) 527 pixel = PyInt_AS_LONG(py_pixel); 528 else { 529 PyErr_SetString(PyExc_TypeError, "GdkColormap.query_color: pixel must be" 530 " either int or long"); 531 return NULL; 532 } 533 534 gdk_colormap_query_color(GDK_COLORMAP(self->obj), pixel, &colour); 535 536 return pyg_boxed_new(GDK_TYPE_COLOR, &colour, TRUE, TRUE); 537} 538