``0`` (no attributes).
+.. method:: window.attr_get()
+
+ Return the window's current rendition as a ``(attrs, pair)`` tuple,
+ where *attrs* is the set of attributes and *pair* is the color pair number.
+
+ Unlike :meth:`attron` and friends, which take packed ``A_*`` attributes,
+ this method and the other ``attr_*`` methods work with the
+ :ref:`WA_* attributes <curses-wa-constants>` and keep the color pair as a
+ separate number, which lets them use color pairs that do not fit alongside
+ the attributes in a single value.
+
+ .. versionadded:: next
+
+
+.. method:: window.attr_set(attr, pair=0)
+
+ Set the window's rendition to the attributes *attr* and the color pair *pair*.
+
+ .. versionadded:: next
+
+
+.. method:: window.attr_on(attr)
+
+ Turn on the attributes *attr* without affecting any others.
+
+ .. versionadded:: next
+
+
+.. method:: window.attr_off(attr)
+
+ Turn off the attributes *attr* without affecting any others.
+
+ .. versionadded:: next
+
+
+.. method:: window.color_set(pair)
+
+ Set the window's color pair to *pair*, leaving the other attributes unchanged.
+
+ .. versionadded:: next
+
+
+.. method:: window.getattrs()
+
+ Return the window's current attributes.
+
+ .. versionadded:: next
+
+
.. method:: window.bkgd(ch[, attr])
Set the background property of the window to the character *ch*, with
.. versionadded:: 3.7
``A_ITALIC`` was added.
+.. _curses-wa-constants:
+
+The :meth:`~window.attr_get`, :meth:`~window.attr_set`, :meth:`~window.attr_on`
+and :meth:`~window.attr_off` methods use a parallel set of ``WA_*`` constants.
+These have the same meaning as the corresponding ``A_*`` attributes above
+(``WA_BOLD`` like :const:`A_BOLD`, and so on), but belong to the ``attr_t`` type
+rather than being packed into a character. In ncurses the two sets share the
+same values, but other curses implementations may give them different ones, so
+use the ``WA_*`` constants with the ``attr_*`` methods. The available names are
+``WA_ATTRIBUTES``, ``WA_NORMAL``, ``WA_STANDOUT``, ``WA_UNDERLINE``,
+``WA_REVERSE``, ``WA_BLINK``, ``WA_DIM``, ``WA_BOLD``, ``WA_ALTCHARSET``,
+``WA_INVIS``, ``WA_PROTECT``, ``WA_HORIZONTAL``, ``WA_LEFT``, ``WA_LOW``,
+``WA_RIGHT``, ``WA_TOP``, ``WA_VERTICAL`` and ``WA_ITALIC`` (each available only
+where the platform defines it).
+
+.. versionadded:: next
+ The ``WA_*`` constants were added.
+
Several constants are available to extract corresponding attributes returned
by some methods.
available when built against an ncurses with ``NCURSES_EXT_FUNCS``.
(Contributed by Serhiy Storchaka in :gh:`151776`.)
+* Add the :mod:`curses` window methods :meth:`~curses.window.attr_get`,
+ :meth:`~curses.window.attr_set`, :meth:`~curses.window.attr_on`,
+ :meth:`~curses.window.attr_off` and :meth:`~curses.window.color_set`, which
+ pass the color pair as a separate argument instead of packing it into the
+ attribute value, and the corresponding ``WA_*`` attribute constants.
+ (Contributed by Serhiy Storchaka in :gh:`152219`.)
+
gzip
----
win.scrollok(False)
def test_attributes(self):
- # TODO: attr_get(), attr_set(), ...
win = curses.newwin(5, 15, 5, 2)
win.attron(curses.A_BOLD)
win.attroff(curses.A_BOLD)
win.standout()
win.standend()
+ # The attr_*() family works on attr_t attributes paired with a color
+ # pair, unlike the chtype-based attron()/attroff()/attrset().
+ win.attr_set(curses.A_BOLD | curses.A_UNDERLINE)
+ attrs, pair = win.attr_get()
+ self.assertTrue(attrs & curses.A_BOLD)
+ self.assertTrue(attrs & curses.A_UNDERLINE)
+ self.assertEqual(pair, 0)
+ self.assertEqual(win.getattrs(), attrs)
+
+ win.attr_on(curses.A_REVERSE)
+ self.assertTrue(win.attr_get()[0] & curses.A_REVERSE)
+ win.attr_off(curses.A_REVERSE)
+ self.assertFalse(win.attr_get()[0] & curses.A_REVERSE)
+
+ # color_set() with a real pair needs start_color(); see
+ # test_attr_color_pair. Here only the argument validation is checked,
+ # which fails before wcolor_set() is reached.
+ self.assertRaises(TypeError, win.attr_set, 'x')
+ self.assertRaises(TypeError, win.attr_set, curses.A_BOLD, 'x')
+ self.assertRaises(TypeError, win.attr_on, 'x')
+ self.assertRaises(TypeError, win.color_set, 'x')
+ self.assertRaises(ValueError, win.color_set, -1)
+ self.assertRaises(ValueError, win.attr_set, curses.A_BOLD, -1)
+ # attr_t is unsigned: a negative or too-large attribute overflows.
+ self.assertRaises(OverflowError, win.attr_set, -1)
+ self.assertRaises(OverflowError, win.attr_on, -1)
+ self.assertRaises(OverflowError, win.attr_set, 1 << 64)
+
+ @requires_colors
+ def test_attr_color_pair(self):
+ win = curses.newwin(5, 15, 5, 2)
+ curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
+ win.attr_set(curses.A_BOLD, 1)
+ attrs, pair = win.attr_get()
+ self.assertTrue(attrs & curses.A_BOLD)
+ self.assertEqual(pair, 1)
+ win.color_set(0)
+ self.assertEqual(win.attr_get()[1], 0)
+
@requires_curses_window_meth('chgat')
def test_chgat(self):
win = curses.newwin(5, 15, 5, 2)
self.assertEqual(win.inch(3, 11), b'm'[0] | curses.A_UNDERLINE)
self.assertEqual(win.inch(3, 14), b' '[0] | curses.A_UNDERLINE)
+ # attr_t is unsigned: a negative or too-large attribute overflows.
+ self.assertRaises(TypeError, win.chgat, 'x')
+ self.assertRaises(OverflowError, win.chgat, -1)
+ self.assertRaises(OverflowError, win.chgat, 1 << 64)
+
def test_background(self):
win = curses.newwin(5, 15, 5, 2)
win.addstr(0, 0, 'Lorem ipsum')
--- /dev/null
+Add the :mod:`curses` window methods :meth:`~curses.window.attr_get`,
+:meth:`~curses.window.attr_set`, :meth:`~curses.window.attr_on`,
+:meth:`~curses.window.attr_off` and :meth:`~curses.window.color_set`, which use
+a separate color pair argument instead of packing it into the attribute value,
+and the corresponding ``WA_*`` attribute constants.
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=38e9be01d33927fb]*/
+static int
+attr_converter(PyObject *arg, void *ptr)
+{
+ /* attr_t is unsigned and at least as wide as chtype, so an attribute
+ value must be a non-negative integer that fits in attr_t. */
+ unsigned long attr = PyLong_AsUnsignedLong(arg);
+ if (attr == (unsigned long)-1 && PyErr_Occurred()) {
+ return 0;
+ }
+ if (attr > (unsigned long)(attr_t)-1) {
+ PyErr_Format(PyExc_OverflowError,
+ "attribute value is greater than maximum (%lu)",
+ (unsigned long)(attr_t)-1);
+ return 0;
+ }
+ *(attr_t *)ptr = (attr_t)attr;
+ return 1;
+}
+
+/*[python input]
+class attr_converter(CConverter):
+ type = 'attr_t'
+ converter = 'attr_converter'
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=6132d3d99d3ec25a]*/
+
/*****************************************************************************
The Window Object
******************************************************************************/
return curses_window_check_err(self, rtn, "wattrset", "attrset");
}
+/*[clinic input]
+_curses.window.attr_get
+
+Return the window's attributes and color pair as (attrs, pair).
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_attr_get_impl(PyCursesWindowObject *self)
+/*[clinic end generated code: output=74b3f805a2958fb8 input=1efd3c450a1373ef]*/
+{
+ attr_t attrs;
+ int rtn;
+#if _NCURSES_EXTENDED_COLOR_FUNCS
+ int pair;
+ short legacy_pair;
+ rtn = wattr_get(self->win, &attrs, &legacy_pair, &pair);
+#else
+ short pair;
+ rtn = wattr_get(self->win, &attrs, &pair, NULL);
+#endif
+ if (curses_window_check_err(self, rtn, "wattr_get", "attr_get") == NULL) {
+ return NULL;
+ }
+ return Py_BuildValue("(ki)", (unsigned long)attrs, (int)pair);
+}
+
+/*[clinic input]
+_curses.window.attr_set
+
+ attr: attr
+ pair: pair = 0
+ /
+
+Set the window's attributes and color pair.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_attr_set_impl(PyCursesWindowObject *self, attr_t attr,
+ int pair)
+/*[clinic end generated code: output=756416e0d6345d4a input=b7936bd6b73eb3f2]*/
+{
+ int rtn;
+#if _NCURSES_EXTENDED_COLOR_FUNCS
+ rtn = wattr_set(self->win, attr, 0, &pair);
+#else
+ rtn = wattr_set(self->win, attr, (short)pair, NULL);
+#endif
+ return curses_window_check_err(self, rtn, "wattr_set", "attr_set");
+}
+
+/*[clinic input]
+_curses.window.attr_on
+
+ attr: attr
+ /
+
+Turn on the given attributes without affecting any others.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_attr_on_impl(PyCursesWindowObject *self, attr_t attr)
+/*[clinic end generated code: output=712f13a558c5a6cb input=6a51a3d597ddca4b]*/
+{
+ int rtn = wattr_on(self->win, attr, NULL);
+ return curses_window_check_err(self, rtn, "wattr_on", "attr_on");
+}
+
+/*[clinic input]
+_curses.window.attr_off
+
+ attr: attr
+ /
+
+Turn off the given attributes without affecting any others.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_attr_off_impl(PyCursesWindowObject *self, attr_t attr)
+/*[clinic end generated code: output=ac680aead16f74fa input=c5d778b84030d388]*/
+{
+ int rtn = wattr_off(self->win, attr, NULL);
+ return curses_window_check_err(self, rtn, "wattr_off", "attr_off");
+}
+
+/*[clinic input]
+_curses.window.color_set
+
+ pair: pair
+ /
+
+Set the window's color pair attribute.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_color_set_impl(PyCursesWindowObject *self, int pair)
+/*[clinic end generated code: output=5e9e83f02a29bf1c input=70026f6d411db130]*/
+{
+ int rtn;
+#if _NCURSES_EXTENDED_COLOR_FUNCS
+ rtn = wcolor_set(self->win, 0, &pair);
+#else
+ rtn = wcolor_set(self->win, (short)pair, NULL);
+#endif
+ return curses_window_check_err(self, rtn, "wcolor_set", "color_set");
+}
+
+/*[clinic input]
+_curses.window.getattrs
+
+Return the window's current attributes.
+[clinic start generated code]*/
+
+static PyObject *
+_curses_window_getattrs_impl(PyCursesWindowObject *self)
+/*[clinic end generated code: output=835f499205204ec4 input=bf56a0af5b730bd1]*/
+{
+ return PyLong_FromUnsignedLong((unsigned long)(attr_t)getattrs(self->win));
+}
+
/*[clinic input]
_curses.window.bkgdset
int num = -1;
short color;
attr_t attr = A_NORMAL;
- long lattr;
int use_xy = FALSE;
switch (PyTuple_Size(args)) {
case 1:
- if (!PyArg_ParseTuple(args,"l;attr", &lattr))
+ if (!PyArg_ParseTuple(args,"O&;attr", attr_converter, &attr))
return NULL;
- attr = lattr;
break;
case 2:
- if (!PyArg_ParseTuple(args,"il;n,attr", &num, &lattr))
+ if (!PyArg_ParseTuple(args,"iO&;n,attr", &num, attr_converter, &attr))
return NULL;
- attr = lattr;
break;
case 3:
- if (!PyArg_ParseTuple(args,"iil;y,x,attr", &y, &x, &lattr))
+ if (!PyArg_ParseTuple(args,"iiO&;y,x,attr", &y, &x, attr_converter, &attr))
return NULL;
- attr = lattr;
use_xy = TRUE;
break;
case 4:
- if (!PyArg_ParseTuple(args,"iiil;y,x,n,attr", &y, &x, &num, &lattr))
+ if (!PyArg_ParseTuple(args,"iiiO&;y,x,n,attr", &y, &x, &num, attr_converter, &attr))
return NULL;
- attr = lattr;
use_xy = TRUE;
break;
default:
_CURSES_WINDOW_ATTROFF_METHODDEF
_CURSES_WINDOW_ATTRON_METHODDEF
_CURSES_WINDOW_ATTRSET_METHODDEF
+ _CURSES_WINDOW_ATTR_GET_METHODDEF
+ _CURSES_WINDOW_ATTR_SET_METHODDEF
+ _CURSES_WINDOW_ATTR_ON_METHODDEF
+ _CURSES_WINDOW_ATTR_OFF_METHODDEF
+ _CURSES_WINDOW_COLOR_SET_METHODDEF
+ _CURSES_WINDOW_GETATTRS_METHODDEF
_CURSES_WINDOW_BKGD_METHODDEF
#ifdef HAVE_CURSES_WCHGAT
{
SetDictInt("A_ITALIC", A_ITALIC);
#endif
+ /* The WA_* attributes are used by the attr_t-based functions
+ (attr_get, attr_set, ...). ncurses defines them bit-identically to the
+ matching A_* constants, but X/Open keeps the two sets distinct, so other
+ implementations (such as NetBSD curses) may give them different values. */
+#ifdef WA_ATTRIBUTES
+ SetDictInt("WA_ATTRIBUTES", WA_ATTRIBUTES);
+#endif
+#ifdef WA_NORMAL
+ SetDictInt("WA_NORMAL", WA_NORMAL);
+#endif
+#ifdef WA_STANDOUT
+ SetDictInt("WA_STANDOUT", WA_STANDOUT);
+#endif
+#ifdef WA_UNDERLINE
+ SetDictInt("WA_UNDERLINE", WA_UNDERLINE);
+#endif
+#ifdef WA_REVERSE
+ SetDictInt("WA_REVERSE", WA_REVERSE);
+#endif
+#ifdef WA_BLINK
+ SetDictInt("WA_BLINK", WA_BLINK);
+#endif
+#ifdef WA_DIM
+ SetDictInt("WA_DIM", WA_DIM);
+#endif
+#ifdef WA_BOLD
+ SetDictInt("WA_BOLD", WA_BOLD);
+#endif
+#ifdef WA_ALTCHARSET
+ SetDictInt("WA_ALTCHARSET", WA_ALTCHARSET);
+#endif
+#ifdef WA_INVIS
+ SetDictInt("WA_INVIS", WA_INVIS);
+#endif
+#ifdef WA_PROTECT
+ SetDictInt("WA_PROTECT", WA_PROTECT);
+#endif
+#ifdef WA_HORIZONTAL
+ SetDictInt("WA_HORIZONTAL", WA_HORIZONTAL);
+#endif
+#ifdef WA_LEFT
+ SetDictInt("WA_LEFT", WA_LEFT);
+#endif
+#ifdef WA_LOW
+ SetDictInt("WA_LOW", WA_LOW);
+#endif
+#ifdef WA_RIGHT
+ SetDictInt("WA_RIGHT", WA_RIGHT);
+#endif
+#ifdef WA_TOP
+ SetDictInt("WA_TOP", WA_TOP);
+#endif
+#ifdef WA_VERTICAL
+ SetDictInt("WA_VERTICAL", WA_VERTICAL);
+#endif
+#ifdef WA_ITALIC
+ SetDictInt("WA_ITALIC", WA_ITALIC);
+#endif
+
SetDictInt("COLOR_BLACK", COLOR_BLACK);
SetDictInt("COLOR_RED", COLOR_RED);
SetDictInt("COLOR_GREEN", COLOR_GREEN);
return return_value;
}
+PyDoc_STRVAR(_curses_window_attr_get__doc__,
+"attr_get($self, /)\n"
+"--\n"
+"\n"
+"Return the window\'s attributes and color pair as (attrs, pair).");
+
+#define _CURSES_WINDOW_ATTR_GET_METHODDEF \
+ {"attr_get", (PyCFunction)_curses_window_attr_get, METH_NOARGS, _curses_window_attr_get__doc__},
+
+static PyObject *
+_curses_window_attr_get_impl(PyCursesWindowObject *self);
+
+static PyObject *
+_curses_window_attr_get(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ return _curses_window_attr_get_impl((PyCursesWindowObject *)self);
+}
+
+PyDoc_STRVAR(_curses_window_attr_set__doc__,
+"attr_set($self, attr, pair=0, /)\n"
+"--\n"
+"\n"
+"Set the window\'s attributes and color pair.");
+
+#define _CURSES_WINDOW_ATTR_SET_METHODDEF \
+ {"attr_set", _PyCFunction_CAST(_curses_window_attr_set), METH_FASTCALL, _curses_window_attr_set__doc__},
+
+static PyObject *
+_curses_window_attr_set_impl(PyCursesWindowObject *self, attr_t attr,
+ int pair);
+
+static PyObject *
+_curses_window_attr_set(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ attr_t attr;
+ int pair = 0;
+
+ if (!_PyArg_CheckPositional("attr_set", nargs, 1, 2)) {
+ goto exit;
+ }
+ if (!attr_converter(args[0], &attr)) {
+ goto exit;
+ }
+ if (nargs < 2) {
+ goto skip_optional;
+ }
+ if (!pair_converter(args[1], &pair)) {
+ goto exit;
+ }
+skip_optional:
+ return_value = _curses_window_attr_set_impl((PyCursesWindowObject *)self, attr, pair);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_curses_window_attr_on__doc__,
+"attr_on($self, attr, /)\n"
+"--\n"
+"\n"
+"Turn on the given attributes without affecting any others.");
+
+#define _CURSES_WINDOW_ATTR_ON_METHODDEF \
+ {"attr_on", (PyCFunction)_curses_window_attr_on, METH_O, _curses_window_attr_on__doc__},
+
+static PyObject *
+_curses_window_attr_on_impl(PyCursesWindowObject *self, attr_t attr);
+
+static PyObject *
+_curses_window_attr_on(PyObject *self, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ attr_t attr;
+
+ if (!attr_converter(arg, &attr)) {
+ goto exit;
+ }
+ return_value = _curses_window_attr_on_impl((PyCursesWindowObject *)self, attr);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_curses_window_attr_off__doc__,
+"attr_off($self, attr, /)\n"
+"--\n"
+"\n"
+"Turn off the given attributes without affecting any others.");
+
+#define _CURSES_WINDOW_ATTR_OFF_METHODDEF \
+ {"attr_off", (PyCFunction)_curses_window_attr_off, METH_O, _curses_window_attr_off__doc__},
+
+static PyObject *
+_curses_window_attr_off_impl(PyCursesWindowObject *self, attr_t attr);
+
+static PyObject *
+_curses_window_attr_off(PyObject *self, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ attr_t attr;
+
+ if (!attr_converter(arg, &attr)) {
+ goto exit;
+ }
+ return_value = _curses_window_attr_off_impl((PyCursesWindowObject *)self, attr);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_curses_window_color_set__doc__,
+"color_set($self, pair, /)\n"
+"--\n"
+"\n"
+"Set the window\'s color pair attribute.");
+
+#define _CURSES_WINDOW_COLOR_SET_METHODDEF \
+ {"color_set", (PyCFunction)_curses_window_color_set, METH_O, _curses_window_color_set__doc__},
+
+static PyObject *
+_curses_window_color_set_impl(PyCursesWindowObject *self, int pair);
+
+static PyObject *
+_curses_window_color_set(PyObject *self, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int pair;
+
+ if (!pair_converter(arg, &pair)) {
+ goto exit;
+ }
+ return_value = _curses_window_color_set_impl((PyCursesWindowObject *)self, pair);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_curses_window_getattrs__doc__,
+"getattrs($self, /)\n"
+"--\n"
+"\n"
+"Return the window\'s current attributes.");
+
+#define _CURSES_WINDOW_GETATTRS_METHODDEF \
+ {"getattrs", (PyCFunction)_curses_window_getattrs, METH_NOARGS, _curses_window_getattrs__doc__},
+
+static PyObject *
+_curses_window_getattrs_impl(PyCursesWindowObject *self);
+
+static PyObject *
+_curses_window_getattrs(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ return _curses_window_getattrs_impl((PyCursesWindowObject *)self);
+}
+
PyDoc_STRVAR(_curses_window_bkgdset__doc__,
"bkgdset($self, ch, attr=_curses.A_NORMAL, /)\n"
"--\n"
#ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
#define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF
#endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */
-/*[clinic end generated code: output=fd0f4e65dc594a65 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=3d8d59f44ded2226 input=a9049054013a1b77]*/