984 lines
27 KiB
C++
984 lines
27 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"
|
|
#include"os_predef.h"
|
|
#include"os_std.h"
|
|
#include"os_gl.h"
|
|
|
|
|
|
#include "Err.h"
|
|
|
|
#include "main.h"
|
|
#include "Base.h"
|
|
#include "Pop.h"
|
|
#include "PopUp.h"
|
|
#include "Ortho.h"
|
|
#include "Util.h"
|
|
#include "P.h"
|
|
#include "Util.h"
|
|
#include "Color.h"
|
|
#include "Text.h"
|
|
#include "PyMOL.h"
|
|
#include "CGO.h"
|
|
#include "Block.h"
|
|
|
|
#define cPopUpLineHeight DIP2PIXEL(17)
|
|
#define cPopUpTitleHeight DIP2PIXEL(19)
|
|
#define cPopUpBarHeight DIP2PIXEL(4)
|
|
#define cPopUpCharWidth DIP2PIXEL(8)
|
|
#define cPopUpCharMargin DIP2PIXEL(2)
|
|
#define cPopUpCharLift DIP2PIXEL(2)
|
|
|
|
#define cChildDelay 0.25
|
|
#define cPassiveDelay 0.45
|
|
#define cDirtyDelay 0.05
|
|
|
|
struct CPopUp : public Block {
|
|
Block *Parent {};
|
|
Block *Child {};
|
|
int ChildLine {};
|
|
int LastX {}, LastY {};
|
|
int StartX {}, StartY {};
|
|
int Selected {};
|
|
int Width {}, Height {};
|
|
int NLine {};
|
|
PyObject **Sub {};
|
|
char **Command {};
|
|
char **Text {};
|
|
int *Code {};
|
|
double ChildDelay {};
|
|
double DirtyDelay {};
|
|
double PassiveDelay {};
|
|
int DirtyDelayFlag {};
|
|
int NeverDragged {};
|
|
int PlacementAffinity {};
|
|
|
|
CPopUp(PyMOLGlobals * G) : Block(G){}
|
|
|
|
void draw(CGO *orthoCGO) override;
|
|
int drag(int x, int y, int mod) override;
|
|
int release(int button, int x, int y, int mod) override;
|
|
void reshape(int width, int height) override {};
|
|
};
|
|
|
|
static
|
|
int PopUpConvertY(CPopUp * I, int value, int mode);
|
|
|
|
/*========================================================================
|
|
* If Sub[a] is a list, return it, otherwise assume it's callable so
|
|
* call it, assign the result to Sub[a] and return the result.
|
|
*
|
|
* @param Sub : array of lists or callables
|
|
* @param a : array index
|
|
*/
|
|
static PyObject * SubGetItem(PyMOLGlobals * G, PyObject ** Sub, const int a) {
|
|
#ifndef _PYMOL_NOPY
|
|
PyObject *elem = Sub[a];
|
|
ok_assert(1, elem);
|
|
|
|
if(!PyList_Check(elem)) {
|
|
PBlock(G);
|
|
elem = PyObject_CallObject(elem, nullptr);
|
|
|
|
if(PyErr_Occurred())
|
|
PyErr_Print();
|
|
|
|
Py_DECREF(Sub[a]);
|
|
Sub[a] = elem;
|
|
|
|
PUnblock(G);
|
|
}
|
|
|
|
return elem;
|
|
|
|
ok_except1:
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
static Block *PopUpRecursiveFind(Block * block, int x, int y)
|
|
{
|
|
PyMOLGlobals *G = block->m_G;
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
if(I->Child) { /* favor the child */
|
|
if(PopUpRecursiveFind(I->Child, x, y) == I->Child)
|
|
return block;
|
|
}
|
|
if(block->recursiveFind(x, y) == block) {
|
|
OrthoGrab(G, block);
|
|
return block;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
Block *PopUpNew(PyMOLGlobals * G, int x, int y, int last_x, int last_y,
|
|
int passive, PyObject * list, Block * parent)
|
|
{
|
|
#ifdef _PYMOL_NOPY
|
|
return nullptr;
|
|
#else
|
|
/* assumes blocked threads (calls the Python C API) */
|
|
|
|
int mx, a, l, cl, cmx;
|
|
int dim[2];
|
|
PyObject *elem;
|
|
const char *str, *c;
|
|
int blocked = PAutoBlock(G);
|
|
auto ui_light_bg = SettingGet<InternalGUIMode>(cSetting_internal_gui_mode, G->Setting);
|
|
CPopUp *I = new CPopUp(G);
|
|
|
|
I->reference = (void *) I;
|
|
I->active = false;
|
|
I->TextColor[0] = 1.0F;
|
|
I->TextColor[1] = 1.0F;
|
|
I->TextColor[2] = 1.0F;
|
|
|
|
I->BackColor[0] = 0.1F;
|
|
I->BackColor[1] = 0.1F;
|
|
I->BackColor[2] = 0.1F;
|
|
|
|
if(ui_light_bg != InternalGUIMode::Default) {
|
|
I->TextColor[0] = 0.0F;
|
|
I->TextColor[1] = 0.0F;
|
|
I->TextColor[2] = 0.0F;
|
|
I->BackColor[0] = 1.0F;
|
|
I->BackColor[1] = 1.0F;
|
|
I->BackColor[2] = 1.0F;
|
|
}
|
|
|
|
I->Parent = parent;
|
|
I->Child = nullptr;
|
|
I->NLine = PyList_Size(list);
|
|
I->Text = nullptr;
|
|
I->Command = nullptr;
|
|
I->Code = nullptr;
|
|
I->Selected = -1;
|
|
I->StartX = (I->LastX = last_x);
|
|
I->StartY = (I->LastY = last_y);
|
|
I->ChildDelay = UtilGetSeconds(G) + cChildDelay * 2.5;
|
|
I->PassiveDelay = UtilGetSeconds(G) + cPassiveDelay;
|
|
I->DirtyDelay = false;
|
|
I->DirtyDelayFlag = false;
|
|
I->NeverDragged = true;
|
|
I->PlacementAffinity = 0;
|
|
mx = 1;
|
|
cmx = 1;
|
|
for(a = 0; a < I->NLine; a++) {
|
|
PyObject* item = PyList_GetItem(list, a);
|
|
if (PyList_Size(item) < 2) {
|
|
continue;
|
|
}
|
|
elem = PyList_GetItem(item, 1);
|
|
l = PyString_Size(elem);
|
|
str = PyString_AsString(elem);
|
|
cl = l;
|
|
c = str;
|
|
while(*c) {
|
|
if(TextStartsWithColorCode(c)) { /* discount the markup */
|
|
c += 3;
|
|
cl -= 4;
|
|
}
|
|
c++;
|
|
}
|
|
if(cl > cmx)
|
|
cmx = cl;
|
|
if(l > mx)
|
|
mx = l;
|
|
}
|
|
I->Width = (cmx * cPopUpCharWidth) + 2 * cPopUpCharMargin;
|
|
|
|
dim[0] = I->NLine + 1;
|
|
dim[1] = mx + 1;
|
|
I->Text = (char **) UtilArrayCalloc((unsigned int *) (void *) dim, 2, 1);
|
|
|
|
mx = 1;
|
|
for(a = 0; a < I->NLine; a++) {
|
|
PyObject* item = PyList_GetItem(list, a);
|
|
if (PyList_Size(item) > 2) {
|
|
PyObject* command = PyList_GetItem(item, 2);
|
|
if(PyString_Check(command)) {
|
|
l = PyString_Size(command);
|
|
if(l > mx)
|
|
mx = l;
|
|
}
|
|
}
|
|
}
|
|
dim[0] = I->NLine + 1;
|
|
dim[1] = mx + 1;
|
|
I->Command = (char **) UtilArrayCalloc((unsigned int *) (void *) dim, 2, 1);
|
|
|
|
I->Code = pymol::malloc<int>(I->NLine + 1);
|
|
I->Sub = pymol::calloc<PyObject *>(I->NLine + 1);
|
|
|
|
for(a = 0; a < I->NLine; a++) {
|
|
PyObject *command;
|
|
elem = PyList_GetItem(list, a);
|
|
I->Code[a] = PyInt_AsLong(PyList_GetItem(elem, 0));
|
|
if (I->Code[a] == 0) {
|
|
continue;
|
|
}
|
|
strcpy(I->Text[a], PyString_AsString(PyList_GetItem(elem, 1)));
|
|
if (I->Code[a] == 2) {
|
|
continue;
|
|
}
|
|
command = PyList_GetItem(elem, 2);
|
|
if(command) {
|
|
if(PyString_Check(command)) {
|
|
strcpy(I->Command[a], PyString_AsString(command));
|
|
} else {
|
|
Py_INCREF(command);
|
|
I->Sub[a] = command;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* compute height */
|
|
|
|
I->Height = 1 * cPopUpCharMargin + PopUpConvertY(I, I->NLine, true);
|
|
|
|
I->rect.top = y;
|
|
I->rect.bottom = y - I->Height;
|
|
I->rect.left = x - (I->Width) / 3;
|
|
I->rect.right = x + (2 * I->Width) / 3;
|
|
|
|
PopFitBlock(I);
|
|
|
|
OrthoAttach(G, I, cOrthoTool);
|
|
I->active = true;
|
|
OrthoGrab(G, I);
|
|
OrthoDirty(G);
|
|
|
|
if(passive)
|
|
PyMOL_SetPassive(G->PyMOL, true);
|
|
|
|
PAutoUnblock(G, blocked);
|
|
|
|
OrthoInvalidateDoDraw(G);
|
|
return I;
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int PopUpConvertY(CPopUp * I, int value, int mode)
|
|
{
|
|
int result;
|
|
int a;
|
|
int flag;
|
|
if(mode) {
|
|
result = 0;
|
|
|
|
/* line to height */
|
|
for(a = 0; a < I->NLine; a++) {
|
|
if(a >= value)
|
|
break;
|
|
switch (I->Code[a]) {
|
|
case 0:
|
|
result += cPopUpBarHeight;
|
|
break;
|
|
case 1:
|
|
result += cPopUpLineHeight;
|
|
break;
|
|
case 2:
|
|
result += cPopUpTitleHeight;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
flag = false;
|
|
/* height to line */
|
|
if(value < 0) {
|
|
result = -1;
|
|
} else {
|
|
result = 0;
|
|
for(a = 0; a < I->NLine; a++) {
|
|
switch (I->Code[a]) {
|
|
case 0:
|
|
if(value < cPopUpBarHeight)
|
|
flag = true;
|
|
value -= cPopUpBarHeight;
|
|
break;
|
|
case 1:
|
|
if(value < cPopUpLineHeight)
|
|
flag = true;
|
|
value -= cPopUpLineHeight;
|
|
break;
|
|
case 2:
|
|
if(value < cPopUpLineHeight)
|
|
flag = true;
|
|
value -= cPopUpTitleHeight;
|
|
break;
|
|
}
|
|
if(flag)
|
|
break;
|
|
result++;
|
|
}
|
|
if(!flag)
|
|
result = -1;
|
|
else if(result && !I->Code[result])
|
|
result--;
|
|
}
|
|
/* height to line */
|
|
}
|
|
return (result);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
static void PopUpDetachRecursiveChild(Block * block)
|
|
{
|
|
PyMOLGlobals *G = block->m_G;
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
|
|
OrthoDetach(G, block);
|
|
if(I->Child)
|
|
PopUpDetachRecursiveChild(I->Child);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
|
|
static void PopUpForgetChild(Block * block)
|
|
{
|
|
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
I->Child = nullptr;
|
|
}
|
|
|
|
static void PopUpRecursiveDetach(Block * block)
|
|
{
|
|
PyMOLGlobals *G = block->m_G;
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
OrthoDetach(G, block);
|
|
if(I->Child)
|
|
PopUpDetachRecursiveChild(I->Child);
|
|
if(I->Parent) {
|
|
PopUpForgetChild(I->Parent);
|
|
PopUpRecursiveDetach(I->Parent);
|
|
}
|
|
}
|
|
|
|
static void PopUpFree(Block * block)
|
|
{
|
|
PyMOLGlobals *G = block->m_G;
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
|
|
#ifndef _PYMOL_NOPY
|
|
{ /* purge code */
|
|
int a;
|
|
int blocked = PAutoBlock(G);
|
|
for(a = 0; a < I->NLine; a++)
|
|
if(I->Sub[a]) {
|
|
Py_DECREF(I->Sub[a]);
|
|
}
|
|
PAutoUnblock(G, blocked);
|
|
}
|
|
#endif
|
|
|
|
OrthoDetach(G, I);
|
|
FreeP(I->Sub);
|
|
FreeP(I->Code);
|
|
FreeP(I->Command);
|
|
FreeP(I->Text);
|
|
DeleteP(I);
|
|
|
|
}
|
|
|
|
static void PopUpRecursiveFree(Block * block)
|
|
{
|
|
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
|
|
if(I->Child)
|
|
PopUpFree(I->Child);
|
|
I->Child = nullptr;
|
|
if(I->Parent) {
|
|
PopUpForgetChild(I->Parent);
|
|
PopUpRecursiveFree(I->Parent);
|
|
}
|
|
PopUpFree(block);
|
|
}
|
|
|
|
static void PopUpFreeRecursiveChild(Block * block)
|
|
{
|
|
CPopUp *I = (CPopUp *) block->reference;
|
|
if(I->Child)
|
|
PopUpFreeRecursiveChild(I->Child);
|
|
I->Child = nullptr;
|
|
PopUpFree(block);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int CPopUp::release(int button, int x, int y, int mod)
|
|
{
|
|
PyMOLGlobals *G = m_G;
|
|
CPopUp *I = (CPopUp *) reference;
|
|
int gone_passive = false;
|
|
|
|
int scroll_dy = 10;
|
|
switch (button) {
|
|
case PYMOL_BUTTON_SCROLL_FORWARD:
|
|
scroll_dy *= -1;
|
|
case PYMOL_BUTTON_SCROLL_REVERSE:
|
|
translate(0, scroll_dy);
|
|
return 1;
|
|
}
|
|
|
|
if(I->NeverDragged) {
|
|
if(I->PassiveDelay > UtilGetSeconds(G)) {
|
|
gone_passive = true;
|
|
I->PassiveDelay = UtilGetSeconds(G); /* kill any further delay */
|
|
}
|
|
}
|
|
if(!gone_passive) {
|
|
if(!I->NeverDragged)
|
|
drag(x, y, mod);
|
|
|
|
/* go passive if we click and release on a sub-menu */
|
|
|
|
if((I->Selected >= 0) && (I->Sub[I->Selected])) {
|
|
if((x >= I->rect.left) && (x <= I->rect.right)) {
|
|
gone_passive = true;
|
|
}
|
|
}
|
|
}
|
|
if(gone_passive) {
|
|
PyMOL_SetPassive(G->PyMOL, true);
|
|
} else {
|
|
OrthoUngrab(G);
|
|
PopUpRecursiveDetach(this);
|
|
if(!I->NeverDragged)
|
|
if((I->Selected >= 0) && (!I->Sub[I->Selected])) {
|
|
PLog(G, I->Command[I->Selected], cPLog_pym);
|
|
PParse(G, I->Command[I->Selected]);
|
|
PFlush(G);
|
|
}
|
|
PopUpRecursiveFree(this);
|
|
}
|
|
OrthoDirty(G);
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int CPopUp::drag(int x, int y, int mod)
|
|
{
|
|
PyMOLGlobals *G = m_G;
|
|
CPopUp *I = (CPopUp *) reference;
|
|
|
|
int a;
|
|
int was = I->Selected;
|
|
|
|
if((!I->NeverDragged) && (((I->StartX - x) > 4) || ((I->StartY - y) > 4)))
|
|
I->NeverDragged = false;
|
|
|
|
I->LastX = x;
|
|
I->LastY = y;
|
|
|
|
x -= I->rect.left;
|
|
y = (I->rect.top - cPopUpCharMargin) - y - 1;
|
|
|
|
if((x < -2) || (x > (I->Width + 2))) {
|
|
int handled_flag = false;
|
|
if(I->Child) {
|
|
if(PopUpRecursiveFind(I->Child, I->LastX, I->LastY) == I->Child) {
|
|
I->Selected = I->ChildLine;
|
|
handled_flag = true;
|
|
}
|
|
}
|
|
if(!handled_flag) {
|
|
if(I->Parent) { /* are we back in the parent window? */
|
|
I->Selected = -1;
|
|
return I->Parent->drag(I->LastX, I->LastY, mod);
|
|
} else if(!I->Child) {
|
|
I->Selected = -1;
|
|
}
|
|
}
|
|
} else {
|
|
OrthoGrab(G, this);
|
|
a = PopUpConvertY(I, y, false);
|
|
if(I->NLine && (a == I->NLine))
|
|
if((y - a * cPopUpLineHeight) < 4)
|
|
a = I->NLine - 1;
|
|
if((a < 0) || (a >= I->NLine))
|
|
I->Selected = -1;
|
|
else {
|
|
if(I->Code[a] == 1) {
|
|
if((I->Child) && (I->ChildLine != a)) {
|
|
if(I->ChildDelay < UtilGetSeconds(G)) {
|
|
PopUpDetachRecursiveChild(I->Child);
|
|
PopUpFreeRecursiveChild(I->Child);
|
|
I->Child = nullptr;
|
|
I->ChildLine = -1;
|
|
OrthoDirty(G);
|
|
OrthoInvalidateDoDraw(G);
|
|
} else {
|
|
I->Selected = a;
|
|
}
|
|
PyMOL_NeedFakeDrag(G->PyMOL);
|
|
}
|
|
}
|
|
|
|
if(I->Code[a] != 1)
|
|
I->Selected = -1;
|
|
else {
|
|
/* activate submenu */
|
|
PyObject * sub_a = SubGetItem(G, I->Sub, a);
|
|
if(!sub_a) {
|
|
// do nothing
|
|
} else if(!I->Child) {
|
|
I->ChildLine = a;
|
|
if(I->ChildDelay > UtilGetSeconds(G)) {
|
|
PyMOL_NeedFakeDrag(G->PyMOL); /* keep coming back here... */
|
|
} else {
|
|
I->Child = PopUpNew(G, I->LastX - 300, I->LastY, I->LastX, I->LastY,
|
|
false, sub_a, I);
|
|
{
|
|
int target_y =
|
|
rect.top - (PopUpConvertY(I, a, true) + cPopUpCharMargin);
|
|
CPopUp *child = (CPopUp *) (I->Child->reference);
|
|
if(child->NLine)
|
|
if(child->Code[0] != 1)
|
|
target_y += cPopUpTitleHeight + 2;
|
|
child->PlacementAffinity = PopPlaceChild(I->Child, rect.left - 5,
|
|
rect.right + 5, target_y,
|
|
I->PlacementAffinity);
|
|
}
|
|
|
|
OrthoGrab(G, this);
|
|
I->ChildDelay = UtilGetSeconds(G) + cChildDelay; /* leave child up for a while */
|
|
}
|
|
PyMOL_NeedFakeDrag(G->PyMOL); /* keep coming back here... */
|
|
} else if(I->ChildLine == a) { /* on correct line */
|
|
I->ChildDelay = UtilGetSeconds(G) + cChildDelay; /* keep child here for a while */
|
|
}
|
|
I->Selected = a;
|
|
}
|
|
}
|
|
}
|
|
/* delay updates, etc. so that child menus
|
|
can be comfortably accessed with sloppy mousing */
|
|
|
|
if((I->Child) && (I->Selected != I->ChildLine))
|
|
PyMOL_NeedFakeDrag(G->PyMOL);
|
|
|
|
if(was != I->Selected) {
|
|
|
|
I->NeverDragged = false;
|
|
if(!I->Child) {
|
|
/* we moved, so renew the child delay */
|
|
I->ChildDelay = UtilGetSeconds(G) + cChildDelay;
|
|
PyMOL_NeedFakeDrag(G->PyMOL);
|
|
}
|
|
|
|
if((I->Child) && (I->Selected != I->ChildLine)) {
|
|
I->DirtyDelayFlag = true;
|
|
I->DirtyDelay = UtilGetSeconds(G) + cDirtyDelay;
|
|
}
|
|
if(!I->DirtyDelayFlag){
|
|
OrthoDirty(G);
|
|
OrthoInvalidateDoDraw(G);
|
|
}
|
|
}
|
|
if(I->DirtyDelayFlag && (I->DirtyDelay < UtilGetSeconds(G))) {
|
|
I->DirtyDelayFlag = false;
|
|
OrthoDirty(G);
|
|
OrthoInvalidateDoDraw(G);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
void CPopUp::draw(CGO* orthoCGO)
|
|
{
|
|
CPopUp *I = this; // TODO: Remove I during PopUp refactor
|
|
PyMOLGlobals *G = m_G;
|
|
int x, y, a, xx;
|
|
char *c;
|
|
|
|
if(G->HaveGUI && G->ValidContext) {
|
|
|
|
if((I->Child) && (I->Selected != I->ChildLine))
|
|
PyMOL_NeedFakeDrag(G->PyMOL);
|
|
|
|
/* put raised border around pop-up menu */
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.2F, 0.2F, 0.4F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.left - 2, rect.bottom - 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 2, rect.bottom - 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.left - 2, rect.bottom + 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 2, rect.bottom + 1, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.2F, 0.2F, 0.4F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.left - 2, rect.bottom - 2);
|
|
glVertex2i(rect.right + 2, rect.bottom - 2);
|
|
glVertex2i(rect.right + 2, rect.bottom + 1);
|
|
glVertex2i(rect.left - 2, rect.bottom + 1);
|
|
glEnd();
|
|
}
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.4F, 0.4F, 0.6F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.left - 1, rect.bottom - 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 1, rect.bottom - 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.left - 1, rect.bottom + 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 1, rect.bottom + 1, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.4F, 0.4F, 0.6F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.left - 1, rect.bottom - 1);
|
|
glVertex2i(rect.right + 1, rect.bottom - 1);
|
|
glVertex2i(rect.right + 1, rect.bottom + 1);
|
|
glVertex2i(rect.left - 1, rect.bottom + 1);
|
|
glEnd();
|
|
}
|
|
/* right */
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.2F, 0.2F, 0.4F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.right, rect.bottom - 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 2, rect.bottom - 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.right, rect.top, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 2, rect.top, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.2F, 0.2F, 0.4F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.right, rect.bottom - 2);
|
|
glVertex2i(rect.right + 2, rect.bottom - 2);
|
|
glVertex2i(rect.right + 2, rect.top);
|
|
glVertex2i(rect.right, rect.top);
|
|
glEnd();
|
|
}
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.4F, 0.4F, 0.6F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.right, rect.bottom - 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 1, rect.bottom - 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.right, rect.top, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 1, rect.top, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.4F, 0.4F, 0.6F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.right, rect.bottom - 1);
|
|
glVertex2i(rect.right + 1, rect.bottom - 1);
|
|
glVertex2i(rect.right + 1, rect.top);
|
|
glVertex2i(rect.right, rect.top);
|
|
glEnd();
|
|
}
|
|
/* top */
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.5F, 0.5F, 0.7F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.left - 2, rect.top + 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 2, rect.top + 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.left - 2, rect.top, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 2, rect.top, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.5F, 0.5F, 0.7F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.left - 2, rect.top + 2);
|
|
glVertex2i(rect.right + 2, rect.top + 2);
|
|
glVertex2i(rect.right + 2, rect.top);
|
|
glVertex2i(rect.left - 2, rect.top);
|
|
glEnd();
|
|
}
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.6F, 0.6F, 0.8F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.left - 1, rect.top + 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 1, rect.top + 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.left - 1, rect.top, 0.f);
|
|
CGOVertex(orthoCGO, rect.right + 1, rect.top, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.6F, 0.6F, 0.8F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.left - 1, rect.top + 1);
|
|
glVertex2i(rect.right + 1, rect.top + 1);
|
|
glVertex2i(rect.right + 1, rect.top);
|
|
glVertex2i(rect.left - 1, rect.top);
|
|
glEnd();
|
|
}
|
|
|
|
/* left */
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.5F, 0.5F, 0.7F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.left - 2, rect.bottom - 2, 0.f);
|
|
CGOVertex(orthoCGO, rect.left, rect.bottom, 0.f);
|
|
CGOVertex(orthoCGO, rect.left - 2, rect.top, 0.f);
|
|
CGOVertex(orthoCGO, rect.left, rect.top, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.5F, 0.5F, 0.7F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.left - 2, rect.bottom - 2);
|
|
glVertex2i(rect.left, rect.bottom);
|
|
glVertex2i(rect.left, rect.top);
|
|
glVertex2i(rect.left - 2, rect.top);
|
|
glEnd();
|
|
}
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.6F, 0.6F, 0.8F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.left - 1, rect.bottom - 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.left, rect.bottom - 1, 0.f);
|
|
CGOVertex(orthoCGO, rect.left, rect.top, 0.f);
|
|
CGOVertex(orthoCGO, rect.left - 1, rect.top, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.6F, 0.6F, 0.8F);
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(rect.left - 1, rect.bottom - 1);
|
|
glVertex2i(rect.left, rect.bottom - 1);
|
|
glVertex2i(rect.left, rect.top);
|
|
glVertex2i(rect.left - 1, rect.top);
|
|
glEnd();
|
|
}
|
|
|
|
if (orthoCGO)
|
|
CGOColorv(orthoCGO, BackColor);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
else
|
|
glColor3fv(BackColor);
|
|
#endif
|
|
fill(orthoCGO);
|
|
|
|
if (orthoCGO)
|
|
CGOColorv(orthoCGO, TextColor);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
else
|
|
glColor3fv(TextColor);
|
|
#endif
|
|
|
|
if(I->Selected >= 0) {
|
|
|
|
x = rect.left;
|
|
y = rect.top - PopUpConvertY(I, I->Selected, true) - cPopUpCharMargin;
|
|
|
|
y += 2;
|
|
if (orthoCGO){
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, x, y, 0.f);
|
|
CGOVertex(orthoCGO, x + I->Width - 1, y, 0.f);
|
|
CGOVertex(orthoCGO, x, y - (cPopUpLineHeight + 3), 0.f);
|
|
CGOVertex(orthoCGO, x + I->Width - 1, y - (cPopUpLineHeight + 3), 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(x, y);
|
|
glVertex2i(x + I->Width - 1, y);
|
|
glVertex2i(x + I->Width - 1, y - (cPopUpLineHeight + 3));
|
|
glVertex2i(x, y - (cPopUpLineHeight + 3));
|
|
glEnd();
|
|
}
|
|
}
|
|
if(I->Code[0] == 2) { /* menu name */
|
|
|
|
if (SettingGet<InternalGUIMode>(cSetting_internal_gui_mode, G->Setting) ==
|
|
InternalGUIMode::Default)
|
|
{
|
|
if (orthoCGO)
|
|
CGOColor(orthoCGO, 0.3F, 0.3F, 0.6F);
|
|
else
|
|
glColor3f(0.3F, 0.3F, 0.6F);
|
|
} else {
|
|
if (orthoCGO)
|
|
CGOColor(orthoCGO, 1.0F, 1.0F, 1.0F);
|
|
else
|
|
glColor3f(1.0F, 1.0F, 1.0F);
|
|
}
|
|
x = rect.left;
|
|
y = rect.top;
|
|
|
|
if (orthoCGO){
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, x, y, 0.f);
|
|
CGOVertex(orthoCGO, x + I->Width, y, 0.f);
|
|
CGOVertex(orthoCGO, x, y - (cPopUpLineHeight + cPopUpCharMargin), 0.f);
|
|
CGOVertex(orthoCGO, x + I->Width, y - (cPopUpLineHeight + cPopUpCharMargin), 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glBegin(GL_POLYGON);
|
|
glVertex2i(x, y);
|
|
glVertex2i(x + I->Width, y);
|
|
glVertex2i(x + I->Width, y - (cPopUpLineHeight + cPopUpCharMargin));
|
|
glVertex2i(x, y - (cPopUpLineHeight + cPopUpCharMargin));
|
|
glEnd();
|
|
}
|
|
|
|
if (orthoCGO){
|
|
CGOColor(orthoCGO, 0.2F, 0.2F, 0.4F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, x + I->Width - 1, y - (cPopUpLineHeight + cPopUpCharMargin), 0.f);
|
|
CGOVertex(orthoCGO, x + I->Width - 1, y - (cPopUpLineHeight + cPopUpCharMargin) - 1.f, 0.f);
|
|
CGOVertex(orthoCGO, x, y - (cPopUpLineHeight + cPopUpCharMargin), 0.f);
|
|
CGOVertex(orthoCGO, x, y - (cPopUpLineHeight + cPopUpCharMargin) - 1.f, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glColor3f(0.2F, 0.2F, 0.4F);
|
|
glBegin(GL_LINES);
|
|
glVertex2i(x + I->Width - 1, y - (cPopUpLineHeight + cPopUpCharMargin));
|
|
glVertex2i(x, y - (cPopUpLineHeight + cPopUpCharMargin));
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
x = rect.left + cPopUpCharMargin;
|
|
y = (rect.top - cPopUpLineHeight) - cPopUpCharMargin + 2;
|
|
|
|
for(a = 0; a < I->NLine; a++) {
|
|
auto text_color = (a == I->Selected) ? BackColor : TextColor;
|
|
TextSetColor(G, text_color);
|
|
if(I->Code[a]) {
|
|
c = I->Text[a];
|
|
xx = x;
|
|
while(*c) {
|
|
// note: previously also supported "\\+++red", but was never used
|
|
if(TextSetColorFromCode(G, c, text_color)) {
|
|
c += 4;
|
|
}
|
|
|
|
TextSetPos2i(G, xx, y + cPopUpCharLift);
|
|
TextDrawChar(G, *(c++), orthoCGO);
|
|
xx = xx + DIP2PIXEL(8);
|
|
}
|
|
|
|
if(I->Sub[a]) {
|
|
|
|
if (orthoCGO){
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOColor(orthoCGO, 0.4F, 0.4F, 0.4F);
|
|
CGOVertex(orthoCGO, rect.left - 3, y + ((cPopUpLineHeight)) - 4, 0.f);
|
|
CGOColor(orthoCGO, 0.4F, 0.4F, 0.4F);
|
|
CGOVertex(orthoCGO, rect.left - 3, y + 1, 0.f);
|
|
CGOColor(orthoCGO, 0.1F, 0.1F, 0.1F);
|
|
CGOVertex(orthoCGO, rect.left, y + ((cPopUpLineHeight)) - 4, 0.f);
|
|
CGOColor(orthoCGO, 0.1F, 0.1F, 0.1F);
|
|
CGOVertex(orthoCGO, rect.left, y + 1, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glBegin(GL_POLYGON);
|
|
glColor3f(0.4F, 0.4F, 0.4F);
|
|
glVertex2i(rect.left - 3, y + 1);
|
|
glColor3f(0.1F, 0.1F, 0.1F);
|
|
glVertex2i(rect.left, y + 1);
|
|
glVertex2i(rect.left, y + ((cPopUpLineHeight)) - 4);
|
|
glColor3f(0.4F, 0.4F, 0.4F);
|
|
glVertex2i(rect.left - 3, y + ((cPopUpLineHeight)) - 4);
|
|
glEnd();
|
|
}
|
|
if (orthoCGO){
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOColor(orthoCGO, 0.1F, 0.2F, 0.2F);
|
|
CGOVertex(orthoCGO, rect.right, y + 1, 0.f);
|
|
CGOColor(orthoCGO, 0.4F, 0.4F, 0.4F);
|
|
CGOVertex(orthoCGO, rect.right + 3, y + 1, 0.f);
|
|
CGOColor(orthoCGO, 0.1F, 0.2F, 0.2F);
|
|
CGOVertex(orthoCGO, rect.right, y + ((cPopUpLineHeight)) - 4, 0.f);
|
|
CGOColor(orthoCGO, 0.4F, 0.4F, 0.4F);
|
|
CGOVertex(orthoCGO, rect.right + 3, y + ((cPopUpLineHeight)) - 4, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glBegin(GL_POLYGON);
|
|
glColor3f(0.1F, 0.2F, 0.2F);
|
|
glVertex2i(rect.right, y + 1);
|
|
glColor3f(0.4F, 0.4F, 0.4F);
|
|
glVertex2i(rect.right + 3, y + 1);
|
|
glVertex2i(rect.right + 3, y + ((cPopUpLineHeight)) - 4);
|
|
glColor3f(0.1F, 0.2F, 0.2F);
|
|
glVertex2i(rect.right, y + ((cPopUpLineHeight)) - 4);
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
y -= cPopUpLineHeight;
|
|
if(I->Code[a] == 2)
|
|
y -= 2;
|
|
} else {
|
|
if (orthoCGO){
|
|
/* two lines between sections in the menu, one light, one dark */
|
|
CGOColor(orthoCGO, 0.3F, 0.3F, 0.5F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.right,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 4, 0.f);
|
|
CGOVertex(orthoCGO, rect.right,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 3, 0.f);
|
|
CGOVertex(orthoCGO, rect.left,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 4, 0.f);
|
|
CGOVertex(orthoCGO, rect.left,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 3, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
CGOColor(orthoCGO, 0.6F, 0.6F, 0.8F);
|
|
CGOBegin(orthoCGO, GL_TRIANGLE_STRIP);
|
|
CGOVertex(orthoCGO, rect.right,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 5, 0.f);
|
|
CGOVertex(orthoCGO, rect.right,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 4, 0.f);
|
|
CGOVertex(orthoCGO, rect.left,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 5, 0.f);
|
|
CGOVertex(orthoCGO, rect.left,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 4, 0.f);
|
|
CGOEnd(orthoCGO);
|
|
} else {
|
|
glBegin(GL_LINES);
|
|
glColor3f(0.3F, 0.3F, 0.5F);
|
|
glVertex2i(rect.left,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 3);
|
|
glVertex2i(rect.right,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 3);
|
|
glColor3f(0.6F, 0.6F, 0.8F);
|
|
glVertex2i(rect.left,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 4);
|
|
glVertex2i(rect.right,
|
|
y + ((cPopUpLineHeight + cPopUpCharMargin) / 2) + 4);
|
|
glEnd();
|
|
}
|
|
y -= cPopUpBarHeight;
|
|
}
|
|
}
|
|
if (orthoCGO)
|
|
CGOColorv(orthoCGO, TextColor);
|
|
#ifndef PURE_OPENGL_ES_2
|
|
else
|
|
glColor3fv(TextColor);
|
|
#endif
|
|
/* BlockOutline(block); */
|
|
}
|
|
}
|