Index: Demo/curses/ncurses.py
===================================================================
--- Demo/curses/ncurses.py (revision 55454)
+++ Demo/curses/ncurses.py (working copy)
@@ -7,6 +7,7 @@
import curses
from curses import panel
+from curses import menu
def wGetchar(win = None):
if win == None: win = stdscr
@@ -64,6 +65,24 @@
win.move(y, x)
win.addch(num)
+def demo_menus(win):
+ global stdscr, nap_msec, mod
+ stdscr = win
+ nap_msec = 1
+ option = -1
+ menu1 = menu.new_menu(5)
+
+ menu1.new_item("option 1", "first option")
+ menu1.new_item("option 2", "second option")
+ menu1.new_item("option 3", "third option")
+ menu1.new_item("option 4", "fourth option")
+ menu1.new_item("option 5", "fifth option")
+ option = menu1.release()
+ saywhat ("Option choisie :" + str(option+1))
+
+ retfree = menu1.free()
+ wait_a_while()
+
def demo_panels(win):
global stdscr, nap_msec, mod
stdscr = win
@@ -71,7 +90,7 @@
mod = ["test", "TEST", "(**)", "*()*", "<-->", "LAST"]
stdscr.refresh()
-
+
for y in range(0, curses.LINES - 1):
for x in range(0, curses.COLS):
stdscr.addstr("%d" % ((y + x) % 10))
@@ -267,7 +286,5 @@
break
nap_msec = 100
-#
-# one fine day there'll be the menu at this place
-#
curses.wrapper(demo_panels)
+curses.wrapper(demo_menus)
Index: setup.py
===================================================================
--- setup.py (revision 55454)
+++ setup.py (working copy)
@@ -981,11 +981,13 @@
# Curses support, requiring the System V version of curses, often
# provided by the ncurses library.
panel_library = 'panel'
+ menu_library = 'menu'
if (self.compiler.find_library_file(lib_dirs, 'ncursesw')):
curses_libs = ['ncursesw']
# Bug 1464056: If _curses.so links with ncursesw,
# _curses_panel.so must link with panelw.
panel_library = 'panelw'
+ menu_library = 'menuw'
exts.append( Extension('_curses', ['_cursesmodule.c'],
libraries = curses_libs) )
elif (self.compiler.find_library_file(lib_dirs, 'ncurses')):
@@ -1016,6 +1018,15 @@
else:
missing.append('_curses_panel')
+ # If the curses module is enabled, check for the menu module
+ if (module_enabled(exts, '_curses') and
+ self.compiler.find_library_file(lib_dirs, menu_library)):
+ exts.append( Extension('_curses_menu', ['_curses_menu.c'],
+ libraries = [menu_library] + curses_libs) )
+ else:
+ missing.append('_curses_menu')
+
+
# Andrew Kuchling's zlib module. Note that some versions of zlib
# 1.1.3 have security problems. See CERT Advisory CA-2002-07:
# http://www.cert.org/advisories/CA-2002-07.html
Index: Modules/_curses_panel.c
===================================================================
--- Modules/_curses_panel.c (revision 55454)
+++ Modules/_curses_panel.c (working copy)
@@ -439,7 +439,6 @@
return Py_None;
}
-
/* List of functions defined in the module */
static PyMethodDef PyCurses_methods[] = {
Index: Modules/_curses_menu.c
===================================================================
--- Modules/_curses_menu.c (revision 0)
+++ Modules/_curses_menu.c (revision 0)
@@ -0,0 +1,267 @@
+/*
+ * Interface to the ncurses menu library
+ *
+ * based on _curses_panel by Thomas Gellekum
+ *
+ * 05/2007 Fabian Frederick
+ * first version : menu & items
+ *
+ */
+
+static char *PyCursesVersion = "2.1";
+
+#include "Python.h"
+#include "py_curses.h"
+#include
+
+static PyObject *PyCursesError;
+
+static PyObject *
+PyCursesCheckERR(int code, char *fname)
+{
+ if (code != ERR) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ } else {
+ if (fname == NULL) {
+ PyErr_SetString(PyCursesError, catchall_ERR);
+ } else {
+ PyErr_Format(PyCursesError, "%s() returned ERR", fname);
+ }
+ return NULL;
+ }
+}
+
+typedef struct {
+ PyObject_HEAD
+ MENU *menu;
+ ITEM **items;
+ int maxitems;
+ int currentitems;
+} PyCursesMenuObject;
+
+PyTypeObject PyCursesMenu_Type;
+
+typedef struct _list_of_menus {
+ PyCursesMenuObject *po;
+ struct _list_of_menus *next;
+} list_of_menus;
+
+/* list anchor */
+static list_of_menus *lom;
+
+static int
+insert_lom(PyCursesMenuObject *po)
+{
+ list_of_menus *new;
+
+ if ((new = (list_of_menus *)malloc(sizeof(list_of_menus))) == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ new->po = po;
+ new->next = lom;
+ lom = new;
+ return 0;
+}
+
+static void
+remove_lom(PyCursesMenuObject *po)
+{
+ list_of_menus *temp, *n;
+
+ temp = lom;
+ if (temp->po == po) {
+ lom = temp->next;
+ free(temp);
+ return;
+ }
+ while (temp->next == NULL || temp->next->po != po) {
+ if (temp->next == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "remove_lom: can't find Menu Object");
+ return;
+ }
+ temp = temp->next;
+ }
+ n = temp->next->next;
+ free(temp->next);
+ temp->next = n;
+ return;
+}
+
+static PyCursesMenuObject *
+find_po(MENU *menu)
+{
+ list_of_menus *temp;
+ for (temp = lom; temp->po->menu != menu; temp = temp->next)
+ if (temp->next == NULL) return NULL; /* not found!? */
+ return temp->po;
+}
+
+static PyObject *
+PyCursesMenu_New(ITEM **items, int maxitems)
+{
+ PyCursesMenuObject *po;
+
+ po = PyObject_NEW(PyCursesMenuObject, &PyCursesMenu_Type);
+ if (po == NULL) return NULL;
+ po->menu = NULL;
+ po->items = items;
+ po->maxitems = maxitems;
+ po->currentitems = 0;
+
+ if (insert_lom(po) < 0) {
+ PyObject_DEL(po);
+ return NULL;
+ }
+ return (PyObject *)po;
+}
+static void
+PyCursesMenu_Dealloc(PyCursesMenuObject *po)
+{
+ remove_lom(po);
+ PyObject_DEL(po);
+}
+
+/*Init menu items (before new_menu)*/
+static PyObject *
+PyCursesMenu_new_item(PyCursesMenuObject *self, PyObject *args)
+{
+ char *itemname;
+ char *itemdesc;
+ if (!PyArg_ParseTuple(args, "ss", &itemname, &itemdesc))
+ return -1;
+ self->items[self->currentitems++]=new_item(itemname, itemdesc);
+ return PyInt_FromLong(1);
+}
+
+/*Init menu items (before new_menu)*/
+static PyObject *
+PyCursesMenu_release(PyCursesMenuObject *self)
+{
+ int key;
+
+ self->menu = new_menu((ITEM **)self->items);
+ post_menu(self->menu);
+ refresh();
+ while((key = getch()) != KEY_F(1)){
+ switch(key){
+ case KEY_DOWN:
+ menu_driver(self->menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(self->menu, REQ_UP_ITEM);
+ break;
+ case 0xA:
+ return (PyInt_FromLong(item_index(current_item(self->menu))));
+ }
+ }
+ return -1;
+}
+
+static PyObject *
+PyCursesMenu_free(PyCursesMenuObject *self)
+{
+ PyObject *result;
+ result=PyInt_FromLong((long)self->currentitems);
+ return result;
+ /*return self->currentitems;*/
+/*
+ for (i = 0;i < self->currentitems;i++)
+ free_item(self->items[i]);
+*/
+/* free_menu(self->menu);*/
+}
+
+/*Class functions ie myclass.new_item*/
+static PyMethodDef PyCursesMenu_Methods[] = {
+ {"new_item", (PyCFunction)PyCursesMenu_new_item, METH_VARARGS},
+ {"release", (PyCFunction)PyCursesMenu_release, METH_NOARGS},
+ {"free", (PyCFunction)PyCursesMenu_free, METH_NOARGS},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+PyCursesMenu_GetAttr(PyCursesMenuObject *self, char *name)
+{
+ return Py_FindMethod(PyCursesMenu_Methods, (PyObject *)self, name);
+}
+
+/* -------------------------------------------------------*/
+
+PyTypeObject PyCursesMenu_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "_curses_menu.curses menu", /*tp_name*/
+ sizeof(PyCursesMenuObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)PyCursesMenu_Dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ (getattrfunc)PyCursesMenu_GetAttr, /*tp_getattr*/
+ (setattrfunc)0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+};
+
+/*New_menu creates python structure and prepares lom item*/
+static PyObject *
+PyCurses_new_menu(PyObject *self, PyObject *args)
+{
+ MENU *menu;
+ ITEM **items;
+ int maxitems;
+
+ if (PyTuple_Size(args) != 1) {
+ PyErr_SetString(PyExc_TypeError, "new_menu requires maximum items as argument");
+ return NULL;
+ }
+ if (!PyArg_ParseTuple(args, "i", &maxitems))
+ return NULL;
+ items = (ITEM **)calloc(maxitems+1, sizeof(ITEM *));
+ items[maxitems] = (ITEM *)NULL;
+
+ return (PyObject *)PyCursesMenu_New(items, maxitems);
+}
+
+
+/*Methods for client*/
+static PyMethodDef PyCurses_methods[] = {
+ {"new_menu", (PyCFunction)PyCurses_new_menu, METH_VARARGS},
+ {"new_item", (PyCFunction)PyCursesMenu_new_item, METH_VARARGS},
+ {"release", (PyCFunction)PyCursesMenu_release, METH_NOARGS},
+ {"free", (PyCFunction)PyCursesMenu_free, METH_NOARGS},
+ {NULL, NULL}
+};
+
+PyMODINIT_FUNC
+init_curses_menu(void)
+{
+ PyObject *m, *d, *v;
+
+ /* Initialize object type */
+ PyCursesMenu_Type.ob_type = &PyType_Type;
+
+ import_curses();
+
+ /* Create the module and add the functions */
+ m = Py_InitModule("_curses_menu", PyCurses_methods);
+ if (m == NULL)
+ return;
+ d = PyModule_GetDict(m);
+
+ /* For exception _curses_menu.error */
+ PyCursesError = PyErr_NewException("_curses_menu.error", NULL, NULL);
+ PyDict_SetItemString(d, "error", PyCursesError);
+
+ /* Make the version available */
+ v = PyString_FromString(PyCursesVersion);
+ PyDict_SetItemString(d, "version", v);
+ PyDict_SetItemString(d, "__version__", v);
+ Py_DECREF(v);
+}