00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 #include "py_commands.h" 00010 #include "VMDTkinterMenu.h" 00011 #include "VMDApp.h" 00012 00013 static const char show_doc[] = 00014 "Show or hide a registered window, or queries window visibility\n\n" 00015 "Args:\n" 00016 " name (str): Window name\n" 00017 " visible (bool): Whether or not window is visible, or None to query" 00018 "Returns:\n" 00019 " (bool): Updated visibility status of menu"; 00020 static PyObject *py_menushow(PyObject *self, PyObject *args, PyObject *kwargs) { 00021 const char *kwlist[] = {"name", "visible", NULL}; 00022 PyObject *shownobj = Py_None; 00023 PyObject *result; 00024 char *name; 00025 00026 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|O!:menu.show", 00027 (char**) kwlist, &name, 00028 &PyBool_Type, &shownobj)) 00029 return NULL; 00030 00031 VMDApp *app; 00032 if (!(app = get_vmdapp())) 00033 return NULL; 00034 00035 // Check menu name actually exists 00036 if (app->menu_id(name) == -1) { 00037 PyErr_Format(PyExc_ValueError, "No such menu '%s' to show/hide", name); 00038 return NULL; 00039 } 00040 00041 // If visible is not None, set visibility of window if (shownobj != Py_None) 00042 app->menu_show(name, PyObject_IsTrue(shownobj)); 00043 00044 // Return visibility status of window 00045 result = app->menu_status(name) ? Py_True : Py_False; 00046 Py_INCREF(result); 00047 return result; 00048 } 00049 00050 00051 static const char loc_doc[] = 00052 "Sets or queries menu location\n\n" 00053 "Args:\n" 00054 " name (str): Menu name\n" 00055 " location (tuple of ints): (x,y) position to set menu location, or None\n" 00056 " to query current menu location\n" 00057 "Returns:\n" 00058 " (tuple of ints): (x, y) updated menu location"; 00059 static PyObject* py_location(PyObject *self, PyObject *args, PyObject *kwargs) { 00060 const char *kwlist[] = {"name", "location", NULL}; 00061 int x = -1, y = -1; 00062 char *name; 00063 00064 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|(ii):menu.location", 00065 (char**) kwlist, &name, &x, &y)) 00066 return NULL; 00067 00068 VMDApp *app; 00069 if (!(app = get_vmdapp())) 00070 return NULL; 00071 00072 // Check menu name actually exists 00073 if (app->menu_id(name) == -1) { 00074 PyErr_Format(PyExc_ValueError, "No such menu '%s' to set location", name); 00075 return NULL; 00076 } 00077 00078 // If a new position is specified, move the menu 00079 if (x != -1 && y != -1) 00080 app->menu_move(name, x, y); 00081 00082 // Return current menu location 00083 app->menu_location(name, x, y); 00084 return Py_BuildValue("(ii)", x, y); 00085 } 00086 00087 00088 static const char add_doc[] = 00089 "Add a new entry to a VMD menu\n\n" 00090 "Args:\n" 00091 " name (str): Name of new menu to add\n" 00092 " root (TKinter menu): Root menu to add this menu under\n"; 00093 static PyObject* py_addmenu(PyObject *self, PyObject *args, PyObject *kwargs) { 00094 const char *kwlist[] = {"name", "root", NULL}; 00095 PyObject *root; 00096 char *name; 00097 00098 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO:menu.add", (char**) kwlist, 00099 &name, &root)) 00100 return NULL; 00101 00102 VMDApp *app; 00103 if (!(app = get_vmdapp())) 00104 return NULL; 00105 00106 // Create the menu 00107 VMDMenu *menu = new VMDTkinterMenu(name, root, app); 00108 00109 // Try to add the menu to the root menu 00110 if (!app->add_menu(menu)) { 00111 delete menu; 00112 PyErr_Format(PyExc_ValueError, "Could not add menu '%s'", name); 00113 return NULL; 00114 } 00115 app->menu_add_extension(name,name); 00116 00117 Py_INCREF(Py_None); 00118 return Py_None; 00119 } 00120 00121 00122 static const char register_doc[] = 00123 "Add an item to a menu and register a function to be called when it is " 00124 "selected.\n\nArgs:\n" 00125 " name (str): Name of menu to add\n" 00126 " function (callable): Function to call when menu selected\n" 00127 " menupath (str): Path to add menu to, if it will be a submenu.\n" 00128 " Defaults to adding to the root menu"; 00129 static PyObject* py_registermenu(PyObject *self, PyObject *args, 00130 PyObject *kwargs) { 00131 const char *kwlist[] = {"name", "function", "menupath", NULL}; 00132 char *menupath = NULL; 00133 PyObject *func; 00134 char *name; 00135 00136 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|s:menu.register", 00137 (char**) kwlist, &name, &func, &menupath)) 00138 return NULL; 00139 00140 // Check that the function is actually a callable 00141 if (!PyCallable_Check(func)) { 00142 PyErr_Format(PyExc_ValueError, "function argument for menu '%s' must " 00143 "be callable", name); 00144 return NULL; 00145 } 00146 00147 // Default for menupath is just being its own menu 00148 if (!menupath) 00149 menupath = name; 00150 00151 // Make a new menu and try to add it to VMD 00152 VMDApp *app; 00153 if (!(app = get_vmdapp())) 00154 return NULL; 00155 00156 VMDTkinterMenu *menu = new VMDTkinterMenu(name, NULL, app); 00157 if (!app->add_menu(menu)) { 00158 delete menu; 00159 PyErr_Format(PyExc_ValueError, "Could not add menu '%s'", name); 00160 return NULL; 00161 } 00162 00163 // Register the callback for the menu 00164 menu->register_windowproc(func); 00165 app->menu_add_extension(name,menupath); 00166 00167 Py_INCREF(Py_None); 00168 return Py_None; 00169 } 00170 00171 00172 static PyMethodDef methods[] = { 00173 {"add", (PyCFunction)py_addmenu, METH_VARARGS | METH_KEYWORDS, add_doc}, 00174 {"register", (PyCFunction)py_registermenu, METH_VARARGS | METH_KEYWORDS, register_doc}, 00175 {"show", (PyCFunction)py_menushow, METH_VARARGS | METH_KEYWORDS, show_doc}, 00176 {"location", (PyCFunction)py_location, METH_VARARGS | METH_KEYWORDS, loc_doc}, 00177 {NULL, NULL} 00178 }; 00179 00180 00181 static const char menu_moddoc[] = 00182 "Methods to manipulate GUI menus"; 00183 00184 00185 #if PY_MAJOR_VERSION >= 3 00186 static struct PyModuleDef menudef = { 00187 PyModuleDef_HEAD_INIT, 00188 "vmdmenu", 00189 menu_moddoc, 00190 -1, 00191 methods, 00192 }; 00193 #endif 00194 00195 00196 PyObject* initvmdmenu(void) { 00197 #if PY_MAJOR_VERSION >= 3 00198 PyObject *m = PyModule_Create(&menudef); 00199 #else 00200 PyObject *m = Py_InitModule3("vmdmenu", methods, menu_moddoc); 00201 #endif 00202 return m; 00203 } 00204