2008-03-25 10:02:13 +00:00
|
|
|
#include "solvespace.h"
|
2010-05-03 05:04:42 +00:00
|
|
|
#include "obj/icons-proto.h"
|
2008-03-25 10:02:13 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
const TextWindow::Color TextWindow::fgColors[] = {
|
|
|
|
{ 'd', RGB(255, 255, 255) },
|
|
|
|
{ 'l', RGB(100, 100, 255) },
|
|
|
|
{ 't', RGB(255, 200, 0) },
|
2008-05-26 09:56:50 +00:00
|
|
|
{ 'h', RGB( 90, 90, 90) },
|
2008-04-28 07:18:39 +00:00
|
|
|
{ 's', RGB( 40, 255, 40) },
|
|
|
|
{ 'm', RGB(200, 200, 0) },
|
|
|
|
{ 'r', RGB( 0, 0, 0) },
|
2008-05-26 09:56:50 +00:00
|
|
|
{ 'x', RGB(255, 20, 20) },
|
2008-06-01 00:26:41 +00:00
|
|
|
{ 'i', RGB( 0, 255, 255) },
|
2008-02-09 13:52:01 +00:00
|
|
|
{ 'g', RGB(160, 160, 160) },
|
2010-05-09 18:25:23 +00:00
|
|
|
{ 'b', RGB(200, 200, 200) },
|
2008-04-28 07:18:39 +00:00
|
|
|
{ 0, 0 },
|
|
|
|
};
|
|
|
|
const TextWindow::Color TextWindow::bgColors[] = {
|
|
|
|
{ 'd', RGB( 0, 0, 0) },
|
2008-05-26 09:56:50 +00:00
|
|
|
{ 't', RGB( 34, 15, 15) },
|
2010-05-09 18:25:23 +00:00
|
|
|
{ 'a', RGB( 25, 25, 25) },
|
2008-04-28 07:18:39 +00:00
|
|
|
{ 'r', RGB(255, 255, 255) },
|
|
|
|
{ 0, 0 },
|
2008-03-28 10:00:37 +00:00
|
|
|
};
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
bool TextWindow::SPACER = false;
|
|
|
|
TextWindow::HideShowIcon TextWindow::hideShowIcons[] = {
|
|
|
|
{ &(SS.GW.showWorkplanes), Icon_workplane, "workplanes from inactive groups"},
|
|
|
|
{ &(SS.GW.showNormals), Icon_normal, "normals" },
|
|
|
|
{ &(SS.GW.showPoints), Icon_point, "points" },
|
|
|
|
{ &(SS.GW.showConstraints), Icon_constraint, "constraints and dimensions" },
|
|
|
|
{ &(SS.GW.showFaces), Icon_faces, "XXX - special cased" },
|
|
|
|
{ &SPACER, 0 },
|
|
|
|
{ &(SS.GW.showShaded), Icon_shaded, "shaded view of solid model" },
|
|
|
|
{ &(SS.GW.showEdges), Icon_edges, "edges of solid model" },
|
|
|
|
{ &(SS.GW.showMesh), Icon_mesh, "triangle mesh of solid model" },
|
|
|
|
{ &SPACER, 0 },
|
|
|
|
{ &(SS.GW.showHdnLines), Icon_hidden_lines, "hidden lines" },
|
|
|
|
{ 0, 0 },
|
|
|
|
};
|
|
|
|
|
2010-04-26 07:52:49 +00:00
|
|
|
void TextWindow::MakeColorTable(const Color *in, float *out) {
|
|
|
|
int i;
|
|
|
|
for(i = 0; in[i].c != 0; i++) {
|
|
|
|
int c = in[i].c;
|
|
|
|
if(c < 0 || c > 255) oops();
|
|
|
|
out[c*3 + 0] = REDf(in[i].color);
|
|
|
|
out[c*3 + 1] = GREENf(in[i].color);
|
|
|
|
out[c*3 + 2] = BLUEf(in[i].color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
void TextWindow::Init(void) {
|
2008-06-01 00:26:41 +00:00
|
|
|
ClearSuper();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextWindow::ClearSuper(void) {
|
|
|
|
HideTextEditControl();
|
2010-04-26 07:52:49 +00:00
|
|
|
|
2008-04-12 14:12:26 +00:00
|
|
|
memset(this, 0, sizeof(*this));
|
2010-04-26 07:52:49 +00:00
|
|
|
MakeColorTable(fgColors, fgColorTable);
|
|
|
|
MakeColorTable(bgColors, bgColorTable);
|
|
|
|
|
2008-06-01 00:26:41 +00:00
|
|
|
ClearScreen();
|
|
|
|
Show();
|
2008-03-26 09:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextWindow::ClearScreen(void) {
|
2008-03-25 10:02:13 +00:00
|
|
|
int i, j;
|
|
|
|
for(i = 0; i < MAX_ROWS; i++) {
|
|
|
|
for(j = 0; j < MAX_COLS; j++) {
|
|
|
|
text[i][j] = ' ';
|
2008-04-28 07:18:39 +00:00
|
|
|
meta[i][j].fg = 'd';
|
|
|
|
meta[i][j].bg = 'd';
|
2008-03-25 10:02:13 +00:00
|
|
|
meta[i][j].link = NOT_A_LINK;
|
|
|
|
}
|
2008-04-28 07:18:39 +00:00
|
|
|
top[i] = i*2;
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
2008-03-26 09:18:12 +00:00
|
|
|
rows = 0;
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
void TextWindow::Printf(bool halfLine, char *fmt, ...) {
|
2008-03-25 10:02:13 +00:00
|
|
|
va_list vl;
|
|
|
|
va_start(vl, fmt);
|
|
|
|
|
2008-04-09 09:35:09 +00:00
|
|
|
if(rows >= MAX_ROWS) return;
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
int r, c;
|
2008-04-09 09:35:09 +00:00
|
|
|
r = rows;
|
2008-04-28 07:18:39 +00:00
|
|
|
top[r] = (r == 0) ? 0 : (top[r-1] + (halfLine ? 3 : 2));
|
2008-04-09 09:35:09 +00:00
|
|
|
rows++;
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
for(c = 0; c < MAX_COLS; c++) {
|
|
|
|
text[r][c] = ' ';
|
|
|
|
meta[r][c].link = NOT_A_LINK;
|
|
|
|
}
|
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
int fg = 'd', bg = 'd';
|
2008-03-28 10:00:37 +00:00
|
|
|
int link = NOT_A_LINK;
|
|
|
|
DWORD data = 0;
|
2008-05-26 09:56:50 +00:00
|
|
|
LinkFunction *f = NULL, *h = NULL;
|
2008-03-25 10:02:13 +00:00
|
|
|
|
|
|
|
c = 0;
|
|
|
|
while(*fmt) {
|
2008-03-28 10:00:37 +00:00
|
|
|
char buf[1024];
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
if(*fmt == '%') {
|
2008-03-26 09:18:12 +00:00
|
|
|
fmt++;
|
|
|
|
if(*fmt == '\0') goto done;
|
2008-03-28 10:00:37 +00:00
|
|
|
strcpy(buf, "");
|
2008-03-26 09:18:12 +00:00
|
|
|
switch(*fmt) {
|
2008-03-28 10:00:37 +00:00
|
|
|
case 'd': {
|
|
|
|
int v = va_arg(vl, int);
|
|
|
|
sprintf(buf, "%d", v);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'x': {
|
|
|
|
DWORD v = va_arg(vl, DWORD);
|
|
|
|
sprintf(buf, "%08x", v);
|
|
|
|
break;
|
|
|
|
}
|
2008-06-11 04:22:52 +00:00
|
|
|
case '@': {
|
|
|
|
double v = va_arg(vl, double);
|
|
|
|
sprintf(buf, "%.2f", v);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case '2': {
|
|
|
|
double v = va_arg(vl, double);
|
|
|
|
sprintf(buf, "%s%.2f", v < 0 ? "" : " ", v);
|
|
|
|
break;
|
|
|
|
}
|
2008-06-01 00:26:41 +00:00
|
|
|
case '3': {
|
|
|
|
double v = va_arg(vl, double);
|
|
|
|
sprintf(buf, "%s%.3f", v < 0 ? "" : " ", v);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-30 10:02:15 +00:00
|
|
|
case '#': {
|
|
|
|
double v = va_arg(vl, double);
|
|
|
|
sprintf(buf, "%.3f", v);
|
|
|
|
break;
|
|
|
|
}
|
2008-03-26 09:18:12 +00:00
|
|
|
case 's': {
|
|
|
|
char *s = va_arg(vl, char *);
|
2008-03-28 10:00:37 +00:00
|
|
|
memcpy(buf, s, min(sizeof(buf), strlen(s)+1));
|
2008-03-26 09:18:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-06-01 00:26:41 +00:00
|
|
|
case 'c': {
|
|
|
|
char v = va_arg(vl, char);
|
2010-05-09 18:25:23 +00:00
|
|
|
if(v == 0) {
|
|
|
|
strcpy(buf, "");
|
|
|
|
} else {
|
|
|
|
sprintf(buf, "%c", v);
|
|
|
|
}
|
2008-06-01 00:26:41 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
case 'E':
|
2008-04-28 07:18:39 +00:00
|
|
|
fg = 'd';
|
|
|
|
// leave the background, though
|
2008-03-28 10:00:37 +00:00
|
|
|
link = NOT_A_LINK;
|
|
|
|
data = 0;
|
|
|
|
f = NULL;
|
2008-05-26 09:56:50 +00:00
|
|
|
h = NULL;
|
2008-03-26 09:18:12 +00:00
|
|
|
break;
|
2008-03-28 10:00:37 +00:00
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
case 'F':
|
|
|
|
case 'B': {
|
|
|
|
int color;
|
2008-03-28 10:00:37 +00:00
|
|
|
if(fmt[1] == '\0') goto done;
|
2008-04-28 07:18:39 +00:00
|
|
|
if(fmt[1] == 'p') {
|
2008-04-11 12:47:14 +00:00
|
|
|
color = va_arg(vl, int);
|
|
|
|
} else {
|
2008-04-28 07:18:39 +00:00
|
|
|
color = fmt[1];
|
2008-04-11 12:47:14 +00:00
|
|
|
}
|
2008-05-30 06:09:41 +00:00
|
|
|
if((color < 0 || color > 255) && !(color & 0x80000000)) {
|
|
|
|
color = 0;
|
|
|
|
}
|
2008-04-28 07:18:39 +00:00
|
|
|
if(*fmt == 'F') {
|
|
|
|
fg = color;
|
|
|
|
} else {
|
|
|
|
bg = color;
|
|
|
|
}
|
|
|
|
fmt++;
|
2008-03-28 10:00:37 +00:00
|
|
|
break;
|
2008-04-28 07:18:39 +00:00
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
case 'L':
|
|
|
|
if(fmt[1] == '\0') goto done;
|
|
|
|
fmt++;
|
2009-09-29 11:35:19 +00:00
|
|
|
if(*fmt == 'p') {
|
|
|
|
link = va_arg(vl, int);
|
|
|
|
} else {
|
|
|
|
link = *fmt;
|
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
break;
|
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
case 'f':
|
|
|
|
f = va_arg(vl, LinkFunction *);
|
|
|
|
break;
|
|
|
|
|
2008-05-26 09:56:50 +00:00
|
|
|
case 'h':
|
|
|
|
h = va_arg(vl, LinkFunction *);
|
|
|
|
break;
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
case 'D':
|
|
|
|
data = va_arg(vl, DWORD);
|
|
|
|
break;
|
|
|
|
|
2008-03-26 09:18:12 +00:00
|
|
|
case '%':
|
2008-03-28 10:00:37 +00:00
|
|
|
strcpy(buf, "%");
|
2008-03-26 09:18:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-03-25 10:02:13 +00:00
|
|
|
} else {
|
2008-03-28 10:00:37 +00:00
|
|
|
buf[0] = *fmt;
|
|
|
|
buf[1]= '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
for(unsigned i = 0; i < strlen(buf); i++) {
|
2008-03-25 10:02:13 +00:00
|
|
|
if(c >= MAX_COLS) goto done;
|
2008-03-28 10:00:37 +00:00
|
|
|
text[r][c] = buf[i];
|
2008-04-28 07:18:39 +00:00
|
|
|
meta[r][c].fg = fg;
|
|
|
|
meta[r][c].bg = bg;
|
2008-03-28 10:00:37 +00:00
|
|
|
meta[r][c].link = link;
|
|
|
|
meta[r][c].data = data;
|
|
|
|
meta[r][c].f = f;
|
2008-05-26 09:56:50 +00:00
|
|
|
meta[r][c].h = h;
|
2008-03-28 10:00:37 +00:00
|
|
|
c++;
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
fmt++;
|
|
|
|
}
|
2008-04-12 14:12:26 +00:00
|
|
|
while(c < MAX_COLS) {
|
2008-04-28 07:18:39 +00:00
|
|
|
meta[r][c].fg = fg;
|
|
|
|
meta[r][c].bg = bg;
|
2008-04-12 14:12:26 +00:00
|
|
|
c++;
|
|
|
|
}
|
2008-03-25 10:02:13 +00:00
|
|
|
|
|
|
|
done:
|
|
|
|
va_end(vl);
|
|
|
|
}
|
|
|
|
|
2008-06-01 00:26:41 +00:00
|
|
|
#define gs (SS.GW.gs)
|
2008-04-12 14:12:26 +00:00
|
|
|
void TextWindow::Show(void) {
|
2008-05-05 06:18:01 +00:00
|
|
|
if(!(SS.GW.pending.operation)) SS.GW.ClearPending();
|
2008-04-13 10:57:41 +00:00
|
|
|
|
2008-05-26 09:56:50 +00:00
|
|
|
SS.GW.GroupSelection();
|
2008-04-12 14:12:26 +00:00
|
|
|
|
2010-05-09 18:25:23 +00:00
|
|
|
// Make sure these tests agree with test used to draw indicator line on
|
|
|
|
// main list of groups screen.
|
2008-05-05 06:18:01 +00:00
|
|
|
if(SS.GW.pending.description) {
|
2008-04-13 10:57:41 +00:00
|
|
|
// A pending operation (that must be completed with the mouse in
|
|
|
|
// the graphics window) will preempt our usual display.
|
2008-06-11 04:22:52 +00:00
|
|
|
HideTextEditControl();
|
2008-06-01 00:26:41 +00:00
|
|
|
ShowHeader(false);
|
2008-04-28 07:18:39 +00:00
|
|
|
Printf(false, "");
|
2008-05-05 06:18:01 +00:00
|
|
|
Printf(false, "%s", SS.GW.pending.description);
|
2008-07-14 04:29:43 +00:00
|
|
|
Printf(true, "%Fl%f%Ll(cancel operation)%E",
|
|
|
|
&TextWindow::ScreenUnselectAll);
|
2009-12-15 12:26:22 +00:00
|
|
|
} else if((gs.n > 0 || gs.constraints > 0) &&
|
|
|
|
shown.screen != SCREEN_PASTE_TRANSFORMED)
|
|
|
|
{
|
2008-06-30 09:09:17 +00:00
|
|
|
if(edit.meaning != EDIT_TTF_TEXT) HideTextEditControl();
|
2008-06-01 00:26:41 +00:00
|
|
|
ShowHeader(false);
|
|
|
|
DescribeSelection();
|
2008-04-13 10:57:41 +00:00
|
|
|
} else {
|
2008-06-30 09:09:17 +00:00
|
|
|
if(edit.meaning == EDIT_TTF_TEXT) HideTextEditControl();
|
2008-06-01 00:26:41 +00:00
|
|
|
ShowHeader(true);
|
2008-07-10 06:11:56 +00:00
|
|
|
switch(shown.screen) {
|
2008-04-13 10:57:41 +00:00
|
|
|
default:
|
2008-07-10 06:11:56 +00:00
|
|
|
shown.screen = SCREEN_LIST_OF_GROUPS;
|
2008-04-13 10:57:41 +00:00
|
|
|
// fall through
|
2008-04-27 09:03:01 +00:00
|
|
|
case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break;
|
|
|
|
case SCREEN_GROUP_INFO: ShowGroupInfo(); break;
|
2008-05-26 09:56:50 +00:00
|
|
|
case SCREEN_GROUP_SOLVE_INFO: ShowGroupSolveInfo(); break;
|
2008-06-11 04:22:52 +00:00
|
|
|
case SCREEN_CONFIGURATION: ShowConfiguration(); break;
|
2008-07-20 11:27:22 +00:00
|
|
|
case SCREEN_STEP_DIMENSION: ShowStepDimension(); break;
|
2009-09-18 08:14:15 +00:00
|
|
|
case SCREEN_LIST_OF_STYLES: ShowListOfStyles(); break;
|
|
|
|
case SCREEN_STYLE_INFO: ShowStyleInfo(); break;
|
2009-12-15 12:26:22 +00:00
|
|
|
case SCREEN_PASTE_TRANSFORMED: ShowPasteTransformed(); break;
|
2010-01-04 00:35:28 +00:00
|
|
|
case SCREEN_EDIT_VIEW: ShowEditView(); break;
|
2008-04-13 10:57:41 +00:00
|
|
|
}
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
2008-06-13 04:41:27 +00:00
|
|
|
Printf(false, "");
|
2008-04-12 14:12:26 +00:00
|
|
|
InvalidateText();
|
2008-03-26 09:18:12 +00:00
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
void TextWindow::TimerCallback(void)
|
|
|
|
{
|
|
|
|
tooltippedIcon = hoveredIcon;
|
|
|
|
InvalidateText();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextWindow::DrawOrHitTestIcons(int how, double mx, double my)
|
|
|
|
{
|
|
|
|
int width, height;
|
|
|
|
GetTextWindowSize(&width, &height);
|
|
|
|
|
|
|
|
int x = 20, y = 33 + LINE_HEIGHT;
|
|
|
|
y -= scrollPos*(LINE_HEIGHT/2);
|
|
|
|
|
|
|
|
double grey = 30.0/255;
|
|
|
|
double top = y - 28, bot = y + 4;
|
|
|
|
glColor4d(grey, grey, grey, 1.0);
|
|
|
|
glxAxisAlignedQuad(0, width, top, bot);
|
|
|
|
|
|
|
|
HideShowIcon *oldHovered = hoveredIcon;
|
|
|
|
if(how != PAINT) {
|
|
|
|
hoveredIcon = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HideShowIcon *hsi;
|
|
|
|
for(hsi = &(hideShowIcons[0]); hsi->var; hsi++) {
|
|
|
|
if(hsi->var == &SPACER) {
|
|
|
|
// Draw a darker-grey spacer in between the groups of icons.
|
|
|
|
if(how == PAINT) {
|
|
|
|
int l = x, r = l + 4,
|
|
|
|
t = y, b = t - 24;
|
|
|
|
glColor4d(0.17, 0.17, 0.17, 1);
|
|
|
|
glxAxisAlignedQuad(l, r, t, b);
|
|
|
|
}
|
|
|
|
x += 12;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(how == PAINT) {
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslated(x, y-24, 0);
|
|
|
|
// Only thing that matters about the color is the alpha,
|
|
|
|
// should be one for no transparency
|
|
|
|
glColor3d(0, 0, 0);
|
|
|
|
glxDrawPixelsWithTexture(hsi->icon, 24, 24);
|
|
|
|
glPopMatrix();
|
|
|
|
|
|
|
|
if(hsi == hoveredIcon) {
|
|
|
|
glColor4d(1, 1, 0, 0.3);
|
|
|
|
glxAxisAlignedQuad(x - 2, x + 26, y + 2, y - 26);
|
|
|
|
}
|
|
|
|
if(!*(hsi->var)) {
|
|
|
|
glColor4d(1, 0, 0, 0.6);
|
|
|
|
glLineWidth(2);
|
|
|
|
int s = 0, f = 24;
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex2d(x+s, y-s);
|
|
|
|
glVertex2d(x+f, y-f);
|
|
|
|
glVertex2d(x+s, y-f);
|
|
|
|
glVertex2d(x+f, y-s);
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(mx > x - 2 && mx < x + 26 &&
|
|
|
|
my < y + 2 && my > y - 26)
|
|
|
|
{
|
|
|
|
// The mouse is hovered over this icon, so do the tooltip
|
|
|
|
// stuff.
|
|
|
|
if(hsi != tooltippedIcon) {
|
|
|
|
oldMousePos = Point2d::From(mx, my);
|
|
|
|
}
|
|
|
|
if(hsi != oldHovered || how == CLICK) {
|
|
|
|
SetTimerFor(1000);
|
|
|
|
}
|
|
|
|
hoveredIcon = hsi;
|
|
|
|
if(how == CLICK) {
|
|
|
|
SS.GW.ToggleBool(hsi->var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x += 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(how != PAINT && hoveredIcon != oldHovered) {
|
|
|
|
InvalidateText();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tooltippedIcon) {
|
|
|
|
if(how == PAINT) {
|
|
|
|
char str[1024];
|
|
|
|
|
|
|
|
if(tooltippedIcon->icon == Icon_faces) {
|
|
|
|
if(SS.GW.showFaces) {
|
2010-05-09 18:25:23 +00:00
|
|
|
strcpy(str, "Don't make faces selectable with mouse");
|
2010-05-03 05:04:42 +00:00
|
|
|
} else {
|
2010-05-09 18:25:23 +00:00
|
|
|
strcpy(str, "Make faces selectable with mouse");
|
2010-05-03 05:04:42 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sprintf(str, "%s %s", *(tooltippedIcon->var) ? "Hide" : "Show",
|
|
|
|
tooltippedIcon->tip);
|
|
|
|
}
|
|
|
|
|
|
|
|
double ox = oldMousePos.x, oy = oldMousePos.y - LINE_HEIGHT;
|
2010-05-10 01:06:09 +00:00
|
|
|
ox += 3;
|
|
|
|
oy -= 3;
|
2010-05-03 05:04:42 +00:00
|
|
|
int tw = (strlen(str) + 1)*CHAR_WIDTH;
|
|
|
|
ox = min(ox, (width - 25) - tw);
|
|
|
|
oy = max(oy, 5);
|
|
|
|
|
|
|
|
glxCreateBitmapFont();
|
|
|
|
glLineWidth(1);
|
|
|
|
glColor4d(1.0, 1.0, 0.6, 1.0);
|
|
|
|
glxAxisAlignedQuad(ox, ox+tw, oy, oy+LINE_HEIGHT);
|
|
|
|
glColor4d(0.0, 0.0, 0.0, 1.0);
|
|
|
|
glxAxisAlignedLineLoop(ox, ox+tw, oy, oy+LINE_HEIGHT);
|
|
|
|
|
|
|
|
glColor4d(0, 0, 0, 1);
|
|
|
|
glxBitmapText(str, Vector::From(ox+5, oy-3+LINE_HEIGHT, 0));
|
|
|
|
} else {
|
|
|
|
if(!hoveredIcon ||
|
|
|
|
(hoveredIcon != tooltippedIcon))
|
|
|
|
{
|
|
|
|
tooltippedIcon = NULL;
|
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
|
|
|
// And if we're hovered, then we've set a timer that will cause
|
|
|
|
// us to show the tool tip later.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextWindow::Paint(void) {
|
|
|
|
int width, height;
|
|
|
|
GetTextWindowSize(&width, &height);
|
|
|
|
|
2010-04-26 07:52:49 +00:00
|
|
|
// We would like things pixel-exact, to avoid shimmering.
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glClearColor(0, 0, 0, 1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glColor3d(1, 1, 1);
|
|
|
|
|
|
|
|
glTranslated(-1, 1, 0);
|
|
|
|
glScaled(2.0/width, -2.0/height, 1);
|
|
|
|
glTranslated(0, 0, 0);
|
|
|
|
|
|
|
|
halfRows = height / (LINE_HEIGHT/2);
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
int bottom = top[rows-1] + 2;
|
2010-04-26 07:52:49 +00:00
|
|
|
scrollPos = min(scrollPos, bottom - halfRows);
|
|
|
|
scrollPos = max(scrollPos, 0);
|
|
|
|
|
|
|
|
// Let's set up the scroll bar first
|
2010-05-03 05:04:42 +00:00
|
|
|
MoveTextScrollbarTo(scrollPos, top[rows - 1] + 1, halfRows);
|
2010-04-26 07:52:49 +00:00
|
|
|
|
|
|
|
// Create the bitmap font that we're going to use.
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
|
|
// Now paint the window.
|
|
|
|
int r, c, a;
|
2010-05-03 05:04:42 +00:00
|
|
|
for(a = 0; a < 2; a++) {
|
2010-04-26 07:52:49 +00:00
|
|
|
if(a == 0) {
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
} else if(a == 1) {
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glxCreateBitmapFont();
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
for(r = 0; r < rows; r++) {
|
|
|
|
int ltop = top[r];
|
|
|
|
if(ltop < (scrollPos-1)) continue;
|
|
|
|
if(ltop > scrollPos+halfRows) break;
|
2010-04-26 07:52:49 +00:00
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
for(c = 0; c < min((width/CHAR_WIDTH)+1, MAX_COLS); c++) {
|
2010-04-26 07:52:49 +00:00
|
|
|
int x = LEFT_MARGIN + c*CHAR_WIDTH;
|
2010-05-03 05:04:42 +00:00
|
|
|
int y = (ltop-scrollPos)*(LINE_HEIGHT/2) + 4;
|
2010-04-26 07:52:49 +00:00
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
int fg = meta[r][c].fg;
|
|
|
|
int bg = meta[r][c].bg;
|
2010-04-26 07:52:49 +00:00
|
|
|
|
|
|
|
// On the first pass, all the background quads; on the next
|
|
|
|
// pass, all the foreground (i.e., font) quads.
|
|
|
|
if(a == 0) {
|
2010-05-03 05:04:42 +00:00
|
|
|
int bh = LINE_HEIGHT, adj = -2;
|
2010-04-26 07:52:49 +00:00
|
|
|
if(bg & 0x80000000) {
|
|
|
|
glColor3f(REDf(bg), GREENf(bg), BLUEf(bg));
|
|
|
|
bh = CHAR_HEIGHT;
|
2010-05-09 18:25:23 +00:00
|
|
|
adj += 2;
|
2010-04-26 07:52:49 +00:00
|
|
|
} else {
|
|
|
|
glColor3fv(&(bgColorTable[bg*3]));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!(bg == 'd')) {
|
|
|
|
// Move the quad down a bit, so that the descenders
|
|
|
|
// still have the correct background.
|
|
|
|
y += adj;
|
2010-05-03 05:04:42 +00:00
|
|
|
glxAxisAlignedQuad(x, x + CHAR_WIDTH, y, y + bh);
|
2010-04-26 07:52:49 +00:00
|
|
|
y -= adj;
|
|
|
|
}
|
|
|
|
} else if(a == 1) {
|
|
|
|
glColor3fv(&(fgColorTable[fg*3]));
|
2010-05-03 05:04:42 +00:00
|
|
|
glxBitmapCharQuad(text[r][c], x, y + CHAR_HEIGHT);
|
|
|
|
|
|
|
|
// If this is a link and it's hovered, then draw the
|
2010-05-09 18:25:23 +00:00
|
|
|
// underline
|
2010-05-03 05:04:42 +00:00
|
|
|
if(meta[r][c].link && meta[r][c].link != 'n' &&
|
|
|
|
(r == hoveredRow && c == hoveredCol))
|
|
|
|
{
|
|
|
|
int cs = c, cf = c;
|
|
|
|
while(cs >= 0 && meta[r][cs].link &&
|
|
|
|
meta[r][cs].f == meta[r][c].f &&
|
|
|
|
meta[r][cs].data == meta[r][c].data)
|
|
|
|
{
|
|
|
|
cs--;
|
|
|
|
}
|
|
|
|
cs++;
|
|
|
|
|
|
|
|
while( meta[r][cf].link &&
|
|
|
|
meta[r][cf].f == meta[r][c].f &&
|
|
|
|
meta[r][cf].data == meta[r][c].data)
|
|
|
|
{
|
|
|
|
cf++;
|
|
|
|
}
|
2010-05-09 18:25:23 +00:00
|
|
|
|
|
|
|
// But don't underline checkboxes or radio buttons
|
|
|
|
while((text[r][cs] & 0x80 || text[r][cs] == ' ') &&
|
|
|
|
cs < cf)
|
|
|
|
{
|
|
|
|
cs++;
|
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
glEnd();
|
|
|
|
|
2010-05-09 18:25:23 +00:00
|
|
|
// Always use the color of the rightmost character
|
|
|
|
// in the link, so that underline is consistent color
|
|
|
|
fg = meta[r][cf-1].fg;
|
|
|
|
glColor3fv(&(fgColorTable[fg*3]));
|
2010-05-03 05:04:42 +00:00
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glLineWidth(1);
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
int yp = y + CHAR_HEIGHT;
|
|
|
|
glVertex2d(LEFT_MARGIN + cs*CHAR_WIDTH, yp);
|
|
|
|
glVertex2d(LEFT_MARGIN + cf*CHAR_WIDTH, yp);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glBegin(GL_QUADS);
|
2010-04-26 07:52:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
}
|
2010-05-03 05:04:42 +00:00
|
|
|
|
2010-05-09 18:25:23 +00:00
|
|
|
// The line to indicate the column of radio buttons that indicates the
|
|
|
|
// active group.
|
|
|
|
SS.GW.GroupSelection();
|
|
|
|
// Make sure this test agrees with test to determine which screen is drawn
|
|
|
|
if(!SS.GW.pending.description && gs.n == 0 && gs.constraints == 0 &&
|
|
|
|
shown.screen == SCREEN_LIST_OF_GROUPS)
|
|
|
|
{
|
|
|
|
int x = 29, y = 70 + LINE_HEIGHT;
|
|
|
|
y -= scrollPos*(LINE_HEIGHT/2);
|
|
|
|
|
|
|
|
glLineWidth(1);
|
|
|
|
glColor3fv(&(fgColorTable['t'*3]));
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex2d(x, y);
|
|
|
|
glVertex2d(x, y+40);
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
// The header has some icons that are drawn separately from the text
|
|
|
|
DrawOrHitTestIcons(PAINT, 0, 0);
|
2010-04-26 07:52:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TextWindow::MouseEvent(bool leftClick, double x, double y) {
|
|
|
|
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) {
|
|
|
|
if(leftClick) {
|
|
|
|
HideTextEditControl();
|
|
|
|
HideGraphicsEditControl();
|
|
|
|
} else {
|
|
|
|
SetMousePointerToHand(false);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
DrawOrHitTestIcons(leftClick ? CLICK : HOVER, x, y);
|
|
|
|
|
2010-04-26 07:52:49 +00:00
|
|
|
GraphicsWindow::Selection ps = SS.GW.hover;
|
|
|
|
SS.GW.hover.Clear();
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
int prevHoveredRow = hoveredRow,
|
|
|
|
prevHoveredCol = hoveredCol;
|
|
|
|
hoveredRow = 0;
|
|
|
|
hoveredCol = 0;
|
|
|
|
|
2010-04-26 07:52:49 +00:00
|
|
|
// Find the corresponding character in the text buffer
|
|
|
|
int c = (int)((x - LEFT_MARGIN) / CHAR_WIDTH);
|
|
|
|
int hh = (LINE_HEIGHT)/2;
|
|
|
|
y += scrollPos*hh;
|
|
|
|
int r;
|
2010-05-03 05:04:42 +00:00
|
|
|
for(r = 0; r < rows; r++) {
|
|
|
|
if(y >= top[r]*hh && y <= (top[r]+2)*hh) {
|
2010-04-26 07:52:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-05-03 05:04:42 +00:00
|
|
|
if(r >= rows) {
|
2010-04-26 07:52:49 +00:00
|
|
|
SetMousePointerToHand(false);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
hoveredRow = r;
|
|
|
|
hoveredCol = c;
|
|
|
|
|
|
|
|
#define META (meta[r][c])
|
2010-04-26 07:52:49 +00:00
|
|
|
if(leftClick) {
|
|
|
|
if(META.link && META.f) {
|
|
|
|
(META.f)(META.link, META.data);
|
2010-05-03 05:04:42 +00:00
|
|
|
Show();
|
2010-04-26 07:52:49 +00:00
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(META.link) {
|
|
|
|
SetMousePointerToHand(true);
|
|
|
|
if(META.h) {
|
|
|
|
(META.h)(META.link, META.data);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SetMousePointerToHand(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
2010-05-03 05:04:42 +00:00
|
|
|
if((!ps.Equals(&(SS.GW.hover))) ||
|
|
|
|
prevHoveredRow != hoveredRow ||
|
|
|
|
prevHoveredCol != hoveredCol)
|
|
|
|
{
|
2010-04-26 07:52:49 +00:00
|
|
|
InvalidateGraphics();
|
2010-05-03 05:04:42 +00:00
|
|
|
InvalidateText();
|
2010-04-26 07:52:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-03 05:04:42 +00:00
|
|
|
void TextWindow::MouseLeave(void) {
|
|
|
|
tooltippedIcon = NULL;
|
2010-05-03 05:43:42 +00:00
|
|
|
hoveredIcon = NULL;
|
2010-05-03 05:04:42 +00:00
|
|
|
hoveredRow = 0;
|
|
|
|
hoveredCol = 0;
|
|
|
|
InvalidateText();
|
|
|
|
}
|
|
|
|
|
2010-04-26 07:52:49 +00:00
|
|
|
void TextWindow::ScrollbarEvent(int newPos) {
|
2010-05-03 05:04:42 +00:00
|
|
|
int bottom = top[rows-1] + 2;
|
2010-04-26 07:52:49 +00:00
|
|
|
newPos = min(newPos, bottom - halfRows);
|
|
|
|
newPos = max(newPos, 0);
|
|
|
|
|
|
|
|
if(newPos != scrollPos) {
|
|
|
|
scrollPos = newPos;
|
2010-05-03 05:04:42 +00:00
|
|
|
MoveTextScrollbarTo(scrollPos, top[rows - 1] + 1, halfRows);
|
2010-04-26 07:52:49 +00:00
|
|
|
|
|
|
|
if(TextEditControlIsVisible()) {
|
|
|
|
extern int TextEditControlCol, TextEditControlHalfRow;
|
|
|
|
ShowTextEditControl(
|
|
|
|
TextEditControlHalfRow, TextEditControlCol, NULL);
|
|
|
|
}
|
|
|
|
InvalidateText();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|