mirror of
https://github.com/schrodinger/pymol-open-source.git
synced 2026-06-04 20:04:21 +08:00
876 lines
23 KiB
C++
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
|