Files
pymol-open-source/layer1/Wizard.cpp
2025-09-26 12:07:31 -04:00

876 lines
23 KiB
C++

/*
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information.
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-*
-*
-*
Z* -------------------------------------------------------------------
*/
#include"os_python.h"
#ifndef _PYMOL_NOPY
#include"os_predef.h"
#include"os_std.h"
#include"os_gl.h"
#include"Err.h"
#include"main.h"
#include"MemoryDebug.h"
#include"Ortho.h"
#include"P.h"
#include"PConv.h"
#include"PopUp.h"
#include"Wizard.h"
#include"Scene.h"
#include"Executive.h"
#include"Block.h"
#include"Text.h"
#include"CGO.h"
#include"vla.h"
#include"pymol/type_traits.h"
#include "Util2.h"
#define cWizBlank 0
#define cWizTypeText 1
#define cWizTypeButton 2
#define cWizTypePopUp 3
#define cWizEventPick 1
#define cWizEventSelect 2
#define cWizEventKey 4
#define cWizEventSpecial 8
#define cWizEventScene 16
#define cWizEventState 32
#define cWizEventFrame 64
#define cWizEventDirty 128
#define cWizEventView 256
#define cWizEventPosition 512
using cWizEvent_t = int;
struct WizardLine {
int type;
WordType text;
OrthoLineType code;
};
struct CWizard : public Block {
std::vector<unique_PyObject_ptr_auto_gil> Wiz {};
pymol::vla<WizardLine> Line {};
ov_size NLine { 0 };
int Pressed { -1 };
int EventMask { 0 };
int Dirty {};
int LastUpdatedState { -1 };
int LastUpdatedFrame { -1 };
float LastUpdatedPosition[3] {};
SceneViewType LastUpdatedView {};
CWizard(PyMOLGlobals * G) : Block(G) {};
int click(int button, int x, int y, int mod) override;
int drag(int x, int y, int mod) override;
void draw(CGO* orthoCGO) override;
int release(int button, int x, int y, int mod) override;
bool isEventType(cWizEvent_t eventType) const noexcept;
};
#define cWizardLeftMargin DIP2PIXEL(3)
#define cWizardTopMargin 0
#define cWizardClickOffset DIP2PIXEL(2)
void WizardDirty(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
I->Dirty = true;
OrthoDirty(G);
}
int WizardUpdate(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
int result = false;
if(OrthoGetDirty(G)) {
WizardDoDirty(G);
}
{
int frame = SettingGetGlobal_i(G, cSetting_frame);
if(frame != I->LastUpdatedFrame) {
I->LastUpdatedFrame = frame;
WizardDoFrame(G);
}
}
{
int state = SettingGetGlobal_i(G, cSetting_state);
if(state != I->LastUpdatedState) {
I->LastUpdatedState = state;
WizardDoState(G);
}
}
WizardDoPosition(G, false);
WizardDoView(G, false);
if(I->Dirty) {
WizardRefresh(G);
I->Dirty = false;
result = true;
}
return result;
}
void WizardPurgeStack(PyMOLGlobals * G)
{
pymol::pautoblock block(G);
G->Wizard->Wiz.clear();
}
bool CWizard::isEventType(cWizEvent_t eventType) const noexcept
{
return EventMask & eventType;
}
/**
* Calls wizard's method in python
*
* @param wiz wizard
* @param funcName wizard method name
* @param func C/C++ function pointer to call the method (see layer1/P.cpp)
* @param fargs function arguments for func
* @return result of func
*/
template<typename Func, typename... FuncArgs>
auto WizardCallPython(PyMOLGlobals* G, PyObject* wiz, const char* funcName, Func&& func, FuncArgs&&... fargs)
-> decltype(func(std::declval<PyObject*>(), std::declval<const char*>(), fargs...))
{
using result_t = decltype(func(std::declval<PyObject*>(), std::declval<const char*>(), fargs...));
result_t result{};
assert(wiz != nullptr);
if (PyObject_HasAttrString(wiz, funcName)) {
result = func(wiz, funcName, std::forward<FuncArgs>(fargs)...);
PErrPrintIfOccurred(G);
}
return result;
}
/**
* Run when user selects something with the mouse, in a wizard
*/
int WizardDoSelect(PyMOLGlobals* G, const char* name, int state)
{
CWizard *I = G->Wizard;
/* if the event is a selection and we're listening for selections */
if (!I->isEventType(cWizEventSelect)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
/* log if necessary */
auto buf = pymol::string_format("cmd.get_wizard().do_select('''%s''')", name);
PLog(G, buf, cPLog_pym);
/* block and call (in Python) the wizard's do_select */
pymol::pblock block(G);
WizardCallPython(G, wiz, "do_pick_state", PTruthCallStr1i, state + 1);
return WizardCallPython(G, wiz, "do_select", PTruthCallStr, name);
}
/*========================================================================*/
void WizardRefresh(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
char *vla = nullptr;
pymol::pautoblock block(G);
/* get the current prompt */
auto wiz = WizardGet(G);
if (wiz) {
auto P_list = WizardCallPython(G, wiz, "get_prompt", PyObject_CallMethod, "");
if(P_list)
PConvPyListToStringVLA(P_list, &vla);
Py_XDECREF(P_list);
}
OrthoSetWizardPrompt(G, vla);
/* get the current panel list */
I->NLine = 0;
if (wiz) {
I->EventMask = cWizEventPick + cWizEventSelect;
auto i = WizardCallPython(G, wiz, "get_event_mask", PyObject_CallMethod, "");
if (i) {
if(!PConvPyIntToInt(i, &I->EventMask))
I->EventMask = cWizEventPick + cWizEventSelect;
Py_XDECREF(i);
}
auto P_list = WizardCallPython(G, wiz, "get_panel", PyObject_CallMethod, "");
if(P_list) {
if(PyList_Check(P_list)) {
std::size_t ll = PyList_Size(P_list);
I->Line.check(ll);
for(std::size_t a = 0u; a < ll; a++) {
/* fallback defaults */
I->Line[a].text[0] = 0;
I->Line[a].code[0] = 0;
I->Line[a].type = 0;
i = PyList_GetItem(P_list, a);
if(PyList_Check(i))
if(PyList_Size(i) > 2) {
PConvPyObjectToInt(PyList_GetItem(i, 0), &I->Line[a].type);
PConvPyObjectToStrMaxLen(PyList_GetItem(i, 1),
I->Line[a].text, sizeof(WordType) - 1);
PConvPyObjectToStrMaxLen(PyList_GetItem(i, 2),
I->Line[a].code, sizeof(OrthoLineType) - 1);
}
}
I->NLine = ll;
}
Py_XDECREF(P_list);
}
}
if(I->NLine) {
int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
OrthoReshapeWizard(G, LineHeight * I->NLine + 4);
} else {
OrthoReshapeWizard(G, 0);
}
}
/*========================================================================*/
pymol::Result<> WizardSet(PyMOLGlobals * G, PyObject * wiz, bool replace)
{
CWizard *I = G->Wizard;
pymol::pautoblock block(G);
if ((!wiz) || (wiz == Py_None) || (!I->Wiz.empty() && replace)) {
/* remove wizard from stack first */
if (!I->Wiz.empty()) {
auto old_wiz = std::move(I->Wiz.back());
I->Wiz.pop_back();
if (old_wiz) {
/* then call cleanup, etc. */
auto result = WizardCallPython(G, old_wiz.get(), "cleanup", PyObject_CallMethod, "");
PXDecRef(result);
}
}
}
if (wiz && (wiz != Py_None)) { /* push */
I->Wiz.emplace_back(PIncRef(wiz));
}
WizardRefresh(G);
return {};
}
/*========================================================================*/
int WizardActive(PyMOLGlobals * G)
{
return !G->Wizard->Wiz.empty();
}
/*========================================================================*/
Block *WizardGetBlock(PyMOLGlobals * G)
{
return G->Wizard;
}
/*========================================================================*/
int WizardDoPick(PyMOLGlobals * G, int bondFlag, int state)
{
/**
* Run when user picks something
*/
CWizard *I = G->Wizard;
/* process the pick if it happened and we're listening for it */
if (!I->isEventType(cWizEventPick)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
if(bondFlag)
PLog(G, "cmd.get_wizard().do_pick(1)", cPLog_pym);
else
PLog(G, "cmd.get_wizard().do_pick(0)", cPLog_pym);
pymol::pblock block(G);
WizardCallPython(G, wiz, "do_pick_state", PTruthCallStr1i, state + 1);
return WizardCallPython(G, wiz, "do_pick", PTruthCallStr1i, bondFlag);
}
int WizardDoKey(PyMOLGlobals * G, unsigned char k, int x, int y, int mod)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventKey)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
auto buffer = pymol::string_format("cmd.get_wizard().do_key(%d,%d,%d,%d)", k, x, y, mod);
PLog(G, buffer, cPLog_pym);
pymol::pblock block(G);
return WizardCallPython(G, wiz, "do_key", PTruthCallStr4i, k, x, y, mod);
}
int WizardDoPosition(PyMOLGlobals * G, int force)
{
CWizard *I = G->Wizard;
int result = false;
if (!I->isEventType(cWizEventPosition)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
int changed = force;
if(!changed) {
float pos[3];
SceneGetCenter(G, pos);
changed = ((fabs(pos[0] - I->LastUpdatedPosition[0]) > R_SMALL4) ||
(fabs(pos[1] - I->LastUpdatedPosition[1]) > R_SMALL4) ||
(fabs(pos[2] - I->LastUpdatedPosition[2]) > R_SMALL4));
}
if(changed) {
SceneGetCenter(G, I->LastUpdatedPosition);
pymol::pblock block(G);
result = WizardCallPython(G, wiz, "do_position", PTruthCallStr0);
}
return result;
}
int WizardDoView(PyMOLGlobals * G, int force)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventView)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
int result = false;
int changed = force;
if(!changed) {
SceneViewType view;
SceneGetView(G, view);
changed = !SceneViewEqual(view, I->LastUpdatedView);
}
if(changed) {
SceneGetView(G, I->LastUpdatedView);
pymol::pblock block(G);
result = WizardCallPython(G, wiz, "do_view", PTruthCallStr0);
}
return result;
}
int WizardDoScene(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventScene)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
std::string buffer = "cmd.get_wizard().do_scene()";
PLog(G, buffer, cPLog_pym);
pymol::pblock block(G);
return WizardCallPython(G, wiz, "do_scene", PTruthCallStr0);
}
int WizardDoDirty(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventDirty)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
std::string buffer = "cmd.get_wizard().do_dirty()";
PLog(G, buffer, cPLog_pym);
pymol::pblock block(G);
return WizardCallPython(G, wiz, "do_dirty", PTruthCallStr0);
}
int WizardDoState(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventState)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
int state = SettingGet<int>(G, cSetting_state);
auto buffer = pymol::string_format("cmd.get_wizard().do_state(%d)", state);
PLog(G, buffer, cPLog_pym);
pymol::pblock block(G);
return WizardCallPython(G, wiz, "do_state", PTruthCallStr1i, state);
}
int WizardDoFrame(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventFrame)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
int frame = SettingGet<int>(G, cSetting_frame) + 1;
auto buffer = pymol::string_format("cmd.get_wizard().do_frame(%d)", frame);
PLog(G, buffer, cPLog_pym);
pymol::pblock block(G);
return WizardCallPython(G, wiz, "do_frame", PTruthCallStr1i, frame);
}
int WizardDoSpecial(PyMOLGlobals * G, int k, int x, int y, int mod)
{
CWizard *I = G->Wizard;
if (!I->isEventType(cWizEventSpecial)) {
return false;
}
auto wiz = WizardGet(G);
if (!wiz) {
return false;
}
auto buffer = pymol::string_format("cmd.get_wizard().do_special(%d,%d,%d,%d)", k, x, y, mod);
PLog(G, buffer, cPLog_pym);
pymol::pblock block(G);
return WizardCallPython(G, wiz, "do_special", PTruthCallStr4i, k, x, y, mod);
}
/*========================================================================*/
int CWizard::click(int button, int x, int y, int mod)
{
PyMOLGlobals *G = m_G;
CWizard *I = G->Wizard;
int LineHeight = DIP2PIXEL(SettingGet<int>(G, cSetting_internal_gui_control_size));
int a = ((rect.top - (y + cWizardClickOffset)) - cWizardTopMargin) / LineHeight;
if((a >= 0) && ((ov_size) a < I->NLine)) {
switch (I->Line[a].type) {
case cWizTypeButton:
OrthoGrab(G, this);
I->Pressed = (int) a;
OrthoDirty(G);
break;
case cWizTypePopUp:
{
pymol::pblock block(G);
auto wiz = WizardGet(G);
PyObject* menuList = nullptr;
if (wiz) {
menuList = WizardCallPython(G, wiz, "get_menu", PyObject_CallMethod, "s", I->Line[a].code);
}
if(menuList && (menuList != Py_None)) {
int my = rect.top - (cWizardTopMargin + a * LineHeight) - 2;
PopUpNew(G, x, my, x, y, false, menuList, nullptr);
}
Py_XDECREF(menuList);
}
break;
}
}
return (1);
}
/*========================================================================*/
int CWizard::drag(int x, int y, int mod)
{
PyMOLGlobals *G = m_G;
CWizard *I = G->Wizard;
int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
int a;
a = ((rect.top - (y + cWizardClickOffset)) - cWizardTopMargin) / LineHeight;
if((x < rect.left) || (x > rect.right))
a = -1;
if(I->Pressed != a) {
I->Pressed = -1;
OrthoDirty(G);
}
if((a >= 0) && ((ov_size) a < I->NLine)) {
switch (I->Line[a].type) {
case cWizTypeButton:
if(I->Pressed != a) {
I->Pressed = a;
OrthoDirty(G);
}
break;
}
}
return (1);
}
/*========================================================================*/
int CWizard::release(int button, int x, int y, int mod)
{
PyMOLGlobals *G = m_G;
CWizard *I = this; // TODO: Remove during Wizard Refactor
int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
int a;
a = ((rect.top - (y + cWizardClickOffset)) - cWizardTopMargin) / LineHeight;
if(I->Pressed)
I->Pressed = -1;
OrthoDirty(G);
OrthoUngrab(G);
if((a >= 0) && ((ov_size) a < I->NLine)) {
switch (I->Line[a].type) {
case cWizTypeButton:
{
if (WizardGet(G)) {
PLog(G, I->Line[a].code, cPLog_pym);
PParse(G, I->Line[a].code);
PFlush(G);
}
}
break;
}
}
I->Pressed = -1;
return (1);
}
static void draw_button(int x2, int y2, int w, int h, float *light, float *dark,
float *inside , CGO *orthoCGO)
{
if (orthoCGO){
CGOColorv(orthoCGO, light);
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
CGOVertex(orthoCGO, x2, y2, 0.f);
CGOVertex(orthoCGO, x2, y2 + h, 0.f);
CGOVertex(orthoCGO, x2 + w, y2, 0.f);
CGOVertex(orthoCGO, x2 + w, y2 + h, 0.f);
CGOEnd(orthoCGO);
} else {
glColor3fv(light);
glBegin(GL_POLYGON);
glVertex2i(x2, y2);
glVertex2i(x2, y2 + h);
glVertex2i(x2 + w, y2 + h);
glVertex2i(x2 + w, y2);
glEnd();
}
if (orthoCGO){
CGOColorv(orthoCGO, dark);
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
CGOVertex(orthoCGO, x2 + 1, y2, 0.f);
CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
CGOVertex(orthoCGO, x2 + w, y2, 0.f);
CGOVertex(orthoCGO, x2 + w, y2 + h - 1, 0.f);
CGOEnd(orthoCGO);
} else {
glColor3fv(dark);
glBegin(GL_POLYGON);
glVertex2i(x2 + 1, y2);
glVertex2i(x2 + 1, y2 + h - 1);
glVertex2i(x2 + w, y2 + h - 1);
glVertex2i(x2 + w, y2);
glEnd();
}
if(inside) {
if (orthoCGO){
CGOColorv(orthoCGO, inside);
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
CGOVertex(orthoCGO, x2 + 1, y2 + 1, 0.f);
CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
CGOVertex(orthoCGO, x2 + w - 1, y2 + 1, 0.f);
CGOVertex(orthoCGO, x2 + w - 1, y2 + h - 1, 0.f);
CGOEnd(orthoCGO);
} else {
glColor3fv(inside);
glBegin(GL_POLYGON);
glVertex2i(x2 + 1, y2 + 1);
glVertex2i(x2 + 1, y2 + h - 1);
glVertex2i(x2 + w - 1, y2 + h - 1);
glVertex2i(x2 + w - 1, y2 + 1);
glEnd();
}
} else { /* rainbow */
if (orthoCGO){
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
CGOColor(orthoCGO, 0.1F, 1.0F, 0.1F); // green
CGOVertex(orthoCGO, x2 + 1, y2 + h - 1, 0.f);
CGOColor(orthoCGO, 1.0F, 1.0F, 0.1F); // yellow
CGOVertex(orthoCGO, x2 + w - 1, y2 + h - 1, 0.f);
CGOColor(orthoCGO, 1.f, 0.1f, 0.1f); // red
CGOVertex(orthoCGO, x2 + 1, y2 + 1, 0.f);
CGOColor(orthoCGO, 0.1F, 0.1F, 1.0F); // blue
CGOVertex(orthoCGO, x2 + w - 1, y2 + 1, 0.f);
CGOEnd(orthoCGO);
} else {
glBegin(GL_POLYGON);
glColor3f(1.0F, 0.1F, 0.1F);
glVertex2i(x2 + 1, y2 + 1);
glColor3f(0.1F, 1.0F, 0.1F);
glVertex2i(x2 + 1, y2 + h - 1);
glColor3f(1.0F, 1.0F, 0.1F);
glVertex2i(x2 + w - 1, y2 + h - 1);
glColor3f(0.1F, 0.1F, 1.0F);
glVertex2i(x2 + w - 1, y2 + 1);
glEnd();
}
}
}
static void draw_text(PyMOLGlobals * G, char *c, int xx, int yy, float *color , CGO *orthoCGO)
{
TextSetColor(G, color);
while(*c) {
if(TextSetColorFromCode(G, c, color)) {
c += 4;
}
TextSetPos2i(G, xx, yy);
TextDrawChar(G, *(c++), orthoCGO);
xx = xx + DIP2PIXEL(8);
}
}
/*========================================================================*/
void CWizard::draw(CGO* orthoCGO)
{
PyMOLGlobals *G = m_G;
CWizard *I = G->Wizard;
int x, y;
int a;
float buttonTextColor[3] = { 1.0, 1.0, 1.0 };
float buttonActiveColor[3] = { 0.8F, 0.8F, 0.8F };
float dimColor[3] = { 0.45F, 0.45F, 0.45F };
float dimLightEdge[3] = { 0.6F, 0.6F, 0.6F };
float dimDarkEdge[3] = { 0.25F, 0.25F, 0.25F };
float menuBGColor[3] = { 0.5F, 0.5F, 1.0 };
float menuLightEdge[3] = { 0.7F, 0.7F, 0.9F };
float menuDarkEdge[3] = { 0.3F, 0.3F, 0.5F };
float black_color[3] = { 0.0F, 0.0F, 0.0F };
float menuColor[3] = { 0.0, 0.0, 0.0 };
int LineHeight = DIP2PIXEL(SettingGetGlobal_i(G, cSetting_internal_gui_control_size));
int text_lift = (LineHeight / 2) - DIP2PIXEL(5);
float *text_color, *text_color2 = TextColor;
text_color = menuColor;
if(G->HaveGUI && G->ValidContext && ((rect.right - rect.left) > 6)) {
if(SettingGet<InternalGUIMode>(cSetting_internal_gui_mode, G->Setting) == InternalGUIMode::Default) {
if (orthoCGO)
CGOColorv(orthoCGO, BackColor);
#ifndef PURE_OPENGL_ES_2
else
glColor3fv(BackColor);
#endif
fill(orthoCGO);
drawLeftEdge(orthoCGO);
} else {
drawLeftEdge(orthoCGO);
if (orthoCGO)
CGOColor(orthoCGO, .5f, .5f, .5f);
else
glColor3f(0.5, 0.5, 0.5);
drawTopEdge();
text_color2 = OrthoGetOverlayColor(G);
}
if (orthoCGO)
CGOColorv(orthoCGO, TextColor);
#ifndef PURE_OPENGL_ES_2
else
glColor3fv(TextColor);
#endif
x = rect.left + cWizardLeftMargin;
y = (rect.top - LineHeight) - cWizardTopMargin;
for(a = 0; (ov_size) a < I->NLine; a++) {
if(I->Pressed == a) {
draw_button(rect.left + 1, y,
(rect.right - rect.left) - 1,
LineHeight - 1, dimLightEdge, dimDarkEdge, buttonActiveColor, orthoCGO);
/* glColor3f(0.0,0.0,0.0); */
text_color = black_color;
} else {
switch (I->Line[a].type) {
case cWizTypeText:
text_color = text_color2;
glColor3fv(text_color2);
break;
case cWizTypeButton:
draw_button(rect.left + 1, y,
(rect.right - rect.left) - 1,
LineHeight - 1, dimLightEdge, dimDarkEdge, dimColor, orthoCGO);
/* glColor3fv(buttonTextColor); */
text_color = buttonTextColor;
break;
case cWizTypePopUp:
draw_button(rect.left + 1, y,
(rect.right - rect.left) - 1,
LineHeight - 1, menuLightEdge, menuDarkEdge, menuBGColor, orthoCGO);
/* glColor3fv(menuColor); */
text_color = menuColor;
break;
default:
break;
}
}
draw_text(G, I->Line[a].text, x, y + text_lift, text_color, orthoCGO);
/*GrapDrawStr(I->Line[a].text,x+1,y+text_lift); */
y -= LineHeight;
}
}
}
/*========================================================================*/
PyObject* WizardGet(PyMOLGlobals* G)
{
auto I = G->Wizard;
return I->Wiz.empty() ? nullptr : I->Wiz.back().get();
}
/*========================================================================*/
PyObject* WizardGetStack(PyMOLGlobals * G)
{
CWizard *I = G->Wizard;
auto result = PyList_New(I->Wiz.size());
for (std::size_t i = 0; i < I->Wiz.size(); i++) {
auto wiz = I->Wiz[i].get();
Py_INCREF(wiz);
PyList_SetItem(result, i, wiz); /* steals ref */
}
return result;
}
/*========================================================================*/
pymol::Result<> WizardSetStack(PyMOLGlobals * G, PyObject * list)
{
CWizard *I = G->Wizard;
if (list == nullptr || !PyList_Check(list)) {
return pymol::make_error("Invalid list.");
}
WizardPurgeStack(G);
auto size = PyList_Size(list);
pymol::pautoblock block(G);
for (int a = 0; a < size; a++) {
auto wiz = PyList_GetItem(list, a);
I->Wiz.emplace_back(PIncRef(wiz));
}
WizardRefresh(G);
OrthoDirty(G);
return {};
}
/*========================================================================*/
int WizardInit(PyMOLGlobals * G)
{
auto I = new CWizard(G);
G->Wizard = I;
I->active = true;
I->TextColor[0] = 0.2F;
I->TextColor[1] = 1.0F;
I->TextColor[2] = 0.2F;
OrthoAttach(G, I, cOrthoTool);
I->Line.resize(1);
return 1;
}
/*========================================================================*/
void WizardFree(PyMOLGlobals * G)
{
WizardPurgeStack(G);
DeleteP(G->Wizard);
}
std::vector<unique_PyObject_ptr_auto_gil> WizardGetWizardCopies(PyMOLGlobals* G)
{
auto I = G->Wizard;
std::vector<unique_PyObject_ptr_auto_gil> copies;
copies.reserve(I->Wiz.size());
pymol::pautoblock block(G);
for (std::size_t i = 0u; i < I->Wiz.size(); i++) {
copies.emplace_back(PIncRef(I->Wiz[i].get()));
}
return copies;
}
void WizardSetWizards(PyMOLGlobals* G, const std::vector<unique_PyObject_ptr_auto_gil>& wizs)
{
auto I = G->Wizard;
WizardPurgeStack(G);
I->Wiz.reserve(wizs.size());
pymol::pautoblock block(G);
for (std::size_t i = 0u; i < wizs.size(); i++) {
I->Wiz.emplace_back(PIncRef(wizs[i].get()));
}
WizardRefresh(G);
WizardDirty(G);
OrthoDirty(G);
}
#endif