Initial work to move text window guts into platform-independent
code. This is now drawn using gl, and the bitmap font (both there and in the graphics window) is drawn from a texture from a static table, not from the Win32 functions, since that's ~1000x faster. So this adds a tool to generate that table. With luck that will also fix my font issues under WINE, which won't have to render the TTF itself. Still needs some cleanup, and to make all the cosmetic improvements that I want. [git-p4: depot-paths = "//depot/solvespace/": change = 2130]solver
parent
6750995ef0
commit
c4b442f92f
2
Makefile
2
Makefile
|
@ -94,6 +94,8 @@ $(RES): win32/$(@B).rc icon.ico
|
|||
|
||||
toolbar.cpp: $(OBJDIR)/icons.h
|
||||
|
||||
glhelper.cpp: bitmapfont.table font.table
|
||||
|
||||
$(OBJDIR)/icons.h: icons/* png2c.pl
|
||||
perl png2c.pl > $(OBJDIR)/icons.h
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
2
draw.cpp
2
draw.cpp
|
@ -525,7 +525,7 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
if(SS.bgImage.fromFile) {
|
||||
// If a background image is loaded, then we draw it now as a texture.
|
||||
// This handles the resizing for us nicely.
|
||||
glBindTexture(GL_TEXTURE_2D, 10);
|
||||
glBindTexture(GL_TEXTURE_2D, TEXTURE_BACKGROUND_IMG);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
|
|
|
@ -215,10 +215,12 @@ void SolveSpace::GenerateAll(int first, int last, bool andFindFree) {
|
|||
glVertex2d(left, top-height);
|
||||
glEnd();
|
||||
|
||||
glxCreateBitmapFont();
|
||||
glColor3d(0, 0, 0);
|
||||
glPushMatrix();
|
||||
glRasterPos2d(left+8, top-17);
|
||||
DrawWithBitmapFont(msg);
|
||||
glTranslated(left+8, top-20, 0);
|
||||
glScaled(1, -1, 1);
|
||||
glxBitmapText(msg, Vector::From(0, 0, 0));
|
||||
glPopMatrix();
|
||||
glFlush();
|
||||
glDrawBuffer(GL_BACK);
|
||||
|
|
54
glhelper.cpp
54
glhelper.cpp
|
@ -3,6 +3,9 @@
|
|||
// A public-domain Hershey vector font ("Simplex").
|
||||
#include "font.table"
|
||||
|
||||
// A bitmap font.
|
||||
#include "bitmapfont.table"
|
||||
|
||||
static bool ColorLocked;
|
||||
static bool DepthOffsetLocked;
|
||||
|
||||
|
@ -450,3 +453,54 @@ void glxDepthRangeLockToFront(bool yes) {
|
|||
}
|
||||
}
|
||||
|
||||
void glxCreateBitmapFont(void) {
|
||||
glBindTexture(GL_TEXTURE_2D, TEXTURE_BITMAP_FONT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA,
|
||||
16, 128*16,
|
||||
0,
|
||||
GL_ALPHA, GL_UNSIGNED_BYTE,
|
||||
FontTexture);
|
||||
}
|
||||
|
||||
void glxBitmapCharQuad(char c, double x, double y) {
|
||||
int w = SS.TW.CHAR_WIDTH,
|
||||
h = SS.TW.CHAR_HEIGHT;
|
||||
|
||||
if(c != ' ' && c != 0 && c < 128) {
|
||||
double s0 = 0,
|
||||
s1 = h/16.0,
|
||||
t0 = c/128.0,
|
||||
t1 = t0 + (w/16.0)/128;
|
||||
|
||||
glTexCoord2d(s1, t0);
|
||||
glVertex2d(x, y);
|
||||
|
||||
glTexCoord2d(s1, t1);
|
||||
glVertex2d(x + w, y);
|
||||
|
||||
glTexCoord2d(s0, t1);
|
||||
glVertex2d(x + w, y - h);
|
||||
|
||||
glTexCoord2d(s0, t0);
|
||||
glVertex2d(x, y - h);
|
||||
}
|
||||
}
|
||||
|
||||
void glxBitmapText(char *str, Vector p) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBegin(GL_QUADS);
|
||||
while(*str) {
|
||||
glxBitmapCharQuad(*str, p.x, p.y);
|
||||
|
||||
str++;
|
||||
p.x += SS.TW.CHAR_WIDTH;
|
||||
}
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
|
10
solvespace.h
10
solvespace.h
|
@ -131,6 +131,7 @@ BOOL GraphicsEditControlIsVisible(void);
|
|||
void ShowTextEditControl(int hr, int c, char *s);
|
||||
void HideTextEditControl(void);
|
||||
BOOL TextEditControlIsVisible(void);
|
||||
void MoveTextScrollbarTo(int pos, int maxPos, int page);
|
||||
|
||||
#define CONTEXT_SUBMENU (-1)
|
||||
#define CONTEXT_SEPARATOR (-2)
|
||||
|
@ -152,13 +153,11 @@ void dbp(char *str, ...);
|
|||
CO((tri).a), CO((tri).b), CO((tri).c))
|
||||
|
||||
void SetWindowTitle(char *str);
|
||||
void SetMousePointerToHand(bool yes);
|
||||
void DoMessageBox(char *str, int rows, int cols, BOOL error);
|
||||
void SetTimerFor(int milliseconds);
|
||||
void ExitNow(void);
|
||||
|
||||
void DrawWithBitmapFont(char *str);
|
||||
void GetBitmapFontExtent(char *str, int *w, int *h);
|
||||
|
||||
void CnfFreezeString(char *str, char *name);
|
||||
void CnfFreezeDWORD(DWORD v, char *name);
|
||||
void CnfFreezeFloat(float v, char *name);
|
||||
|
@ -222,6 +221,11 @@ void glxColorRGB(DWORD rgb);
|
|||
void glxColorRGBa(DWORD rgb, double a);
|
||||
void glxDepthRangeOffset(int units);
|
||||
void glxDepthRangeLockToFront(bool yes);
|
||||
void glxCreateBitmapFont(void);
|
||||
void glxBitmapText(char *str, Vector p);
|
||||
void glxBitmapCharQuad(char c, double x, double y);
|
||||
#define TEXTURE_BACKGROUND_IMG 10
|
||||
#define TEXTURE_BITMAP_FONT 20
|
||||
|
||||
|
||||
#define arraylen(x) (sizeof((x))/sizeof((x)[0]))
|
||||
|
|
182
textwin.cpp
182
textwin.cpp
|
@ -22,13 +22,28 @@ const TextWindow::Color TextWindow::bgColors[] = {
|
|||
{ 0, 0 },
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void TextWindow::Init(void) {
|
||||
ClearSuper();
|
||||
}
|
||||
|
||||
void TextWindow::ClearSuper(void) {
|
||||
HideTextEditControl();
|
||||
|
||||
memset(this, 0, sizeof(*this));
|
||||
MakeColorTable(fgColors, fgColorTable);
|
||||
MakeColorTable(bgColors, bgColorTable);
|
||||
|
||||
ClearScreen();
|
||||
Show();
|
||||
}
|
||||
|
@ -244,3 +259,170 @@ void TextWindow::Show(void) {
|
|||
InvalidateText();
|
||||
}
|
||||
|
||||
void TextWindow::Paint(int width, int height) {
|
||||
// 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);
|
||||
|
||||
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
|
||||
scrollPos = min(scrollPos, bottom - halfRows);
|
||||
scrollPos = max(scrollPos, 0);
|
||||
|
||||
// Let's set up the scroll bar first
|
||||
MoveTextScrollbarTo(scrollPos, SS.TW.top[SS.TW.rows - 1] + 1, halfRows);
|
||||
|
||||
// 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;
|
||||
for(a = 0; a < 3; a++) {
|
||||
if(a == 0) {
|
||||
glBegin(GL_QUADS);
|
||||
} else if(a == 1) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glxCreateBitmapFont();
|
||||
glBegin(GL_QUADS);
|
||||
} else {
|
||||
glBegin(GL_LINES);
|
||||
}
|
||||
|
||||
for(r = 0; r < SS.TW.rows; r++) {
|
||||
int top = SS.TW.top[r];
|
||||
if(top < (scrollPos-1)) continue;
|
||||
if(top > scrollPos+halfRows) break;
|
||||
|
||||
for(c = 0; c < min((width/CHAR_WIDTH)+1, SS.TW.MAX_COLS); c++) {
|
||||
int x = LEFT_MARGIN + c*CHAR_WIDTH;
|
||||
int y = (top-scrollPos)*(LINE_HEIGHT/2) + 2;
|
||||
|
||||
int fg = SS.TW.meta[r][c].fg;
|
||||
int bg = SS.TW.meta[r][c].bg;
|
||||
|
||||
// On the first pass, all the background quads; on the next
|
||||
// pass, all the foreground (i.e., font) quads.
|
||||
if(a == 0) {
|
||||
int bh = LINE_HEIGHT, adj = 0;
|
||||
if(bg & 0x80000000) {
|
||||
glColor3f(REDf(bg), GREENf(bg), BLUEf(bg));
|
||||
bh = CHAR_HEIGHT;
|
||||
adj = 2;
|
||||
} 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;
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2d(x, y);
|
||||
glVertex2d(x + CHAR_WIDTH, y);
|
||||
glVertex2d(x + CHAR_WIDTH, y + bh);
|
||||
glVertex2d(x, y + bh);
|
||||
glEnd();
|
||||
y -= adj;
|
||||
}
|
||||
} else if(a == 1) {
|
||||
glColor3fv(&(fgColorTable[fg*3]));
|
||||
glxBitmapCharQuad(SS.TW.text[r][c], x, y + CHAR_HEIGHT);
|
||||
} else {
|
||||
if(SS.TW.meta[r][c].link && SS.TW.meta[r][c].link != 'n') {
|
||||
glColor3fv(&(fgColorTable[fg*3]));
|
||||
y += CHAR_HEIGHT + 1;
|
||||
glVertex2d(x, y);
|
||||
glVertex2d(x + CHAR_WIDTH, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
void TextWindow::MouseEvent(bool leftClick, double x, double y) {
|
||||
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) {
|
||||
if(leftClick) {
|
||||
HideTextEditControl();
|
||||
HideGraphicsEditControl();
|
||||
} else {
|
||||
SetMousePointerToHand(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GraphicsWindow::Selection ps = SS.GW.hover;
|
||||
SS.GW.hover.Clear();
|
||||
|
||||
// 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;
|
||||
for(r = 0; r < SS.TW.rows; r++) {
|
||||
if(y >= SS.TW.top[r]*hh && y <= (SS.TW.top[r]+2)*hh) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(r >= SS.TW.rows) {
|
||||
SetMousePointerToHand(false);
|
||||
goto done;
|
||||
}
|
||||
|
||||
#define META (SS.TW.meta[r][c])
|
||||
if(leftClick) {
|
||||
if(META.link && META.f) {
|
||||
(META.f)(META.link, META.data);
|
||||
SS.TW.Show();
|
||||
InvalidateGraphics();
|
||||
}
|
||||
} else {
|
||||
if(META.link) {
|
||||
SetMousePointerToHand(true);
|
||||
if(META.h) {
|
||||
(META.h)(META.link, META.data);
|
||||
}
|
||||
} else {
|
||||
SetMousePointerToHand(false);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if(!ps.Equals(&(SS.GW.hover))) {
|
||||
InvalidateGraphics();
|
||||
}
|
||||
}
|
||||
|
||||
void TextWindow::ScrollbarEvent(int newPos) {
|
||||
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
|
||||
newPos = min(newPos, bottom - halfRows);
|
||||
newPos = max(newPos, 0);
|
||||
|
||||
if(newPos != scrollPos) {
|
||||
scrollPos = newPos;
|
||||
MoveTextScrollbarTo(scrollPos, SS.TW.top[SS.TW.rows - 1] + 1, halfRows);
|
||||
|
||||
if(TextEditControlIsVisible()) {
|
||||
extern int TextEditControlCol, TextEditControlHalfRow;
|
||||
ShowTextEditControl(
|
||||
TextEditControlHalfRow, TextEditControlCol, NULL);
|
||||
}
|
||||
InvalidateText();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
toolbar.cpp
12
toolbar.cpp
|
@ -209,6 +209,7 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
|
|||
if(paint) {
|
||||
// Do this last so that nothing can draw over it.
|
||||
if(toolTip.show) {
|
||||
glxCreateBitmapFont();
|
||||
char str[1024];
|
||||
if(strlen(toolTip.str) >= 200) oops();
|
||||
strcpy(str, toolTip.str);
|
||||
|
@ -229,10 +230,8 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
|
|||
}
|
||||
}
|
||||
|
||||
int tw, th;
|
||||
GetBitmapFontExtent(str, &tw, &th);
|
||||
tw += 10;
|
||||
th += 2;
|
||||
int tw = strlen(str)*SS.TW.CHAR_WIDTH + 10,
|
||||
th = SS.TW.LINE_HEIGHT + 2;
|
||||
|
||||
double ox = toolbarMouseX + 3, oy = toolbarMouseY + 3;
|
||||
glLineWidth(1);
|
||||
|
@ -253,8 +252,9 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
|
|||
|
||||
glColor4d(0, 0, 0, 1);
|
||||
glPushMatrix();
|
||||
glRasterPos2d(ox+6, oy+6);
|
||||
DrawWithBitmapFont(str);
|
||||
glTranslated(ox+5, oy+3, 0);
|
||||
glScaled(1, -1, 1);
|
||||
glxBitmapText(str, Vector::From(0, 0, 0));
|
||||
glPopMatrix();
|
||||
}
|
||||
glxDepthRangeLockToFront(false);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
all:
|
||||
cl ttf2c.cpp user32.lib gdi32.lib comctl32.lib
|
||||
ttf2c.exe > ..\bitmapfont.table
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Entry point into the program.
|
||||
//-----------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
InitCommonControls();
|
||||
|
||||
// A monospaced font
|
||||
HFONT font = CreateFont(16, 9, 0, 0, FW_REGULAR, FALSE,
|
||||
FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||||
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
|
||||
|
||||
HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
|
||||
HBITMAP bitmap = CreateCompatibleBitmap(hdc, 30, 30);
|
||||
|
||||
SelectObject(hdc, bitmap);
|
||||
SelectObject(hdc, font);
|
||||
|
||||
printf("static const BYTE FontTexture[] = {\n");
|
||||
|
||||
int c;
|
||||
for(c = 0; c < 128; c++) {
|
||||
|
||||
RECT r;
|
||||
r.left = 0; r.top = 0;
|
||||
r.right = 30; r.bottom = 30;
|
||||
FillRect(hdc, &r, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
||||
|
||||
SetBkColor(hdc, RGB(0, 0, 0));
|
||||
SetTextColor(hdc, RGB(255, 255, 255));
|
||||
char str[2] = { c, 0 };
|
||||
TextOut(hdc, 0, 0, str, 1);
|
||||
|
||||
int i, j;
|
||||
for(i = 0; i < 16; i++) {
|
||||
for(j = 0; j < 16; j++) {
|
||||
COLORREF c = GetPixel(hdc, i, j);
|
||||
printf("%3d, ", c ? 255 : 0);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("};\n");
|
||||
|
||||
return 0;
|
||||
}
|
19
ui.h
19
ui.h
|
@ -5,6 +5,7 @@
|
|||
class TextWindow {
|
||||
public:
|
||||
static const int MAX_COLS = 100;
|
||||
static const int MIN_COLS = 45;
|
||||
static const int MAX_ROWS = 2000;
|
||||
|
||||
#ifndef RGB
|
||||
|
@ -24,6 +25,17 @@ public:
|
|||
static const Color fgColors[];
|
||||
static const Color bgColors[];
|
||||
|
||||
float bgColorTable[256*3];
|
||||
float fgColorTable[256*3];
|
||||
|
||||
static const int CHAR_WIDTH = 9;
|
||||
static const int CHAR_HEIGHT = 16;
|
||||
static const int LINE_HEIGHT = 20;
|
||||
static const int LEFT_MARGIN = 4;
|
||||
|
||||
int scrollPos; // The scrollbar position, in half-row units
|
||||
int halfRows; // The height of our window, in half-row units
|
||||
|
||||
BYTE text[MAX_ROWS][MAX_COLS];
|
||||
typedef void LinkFunction(int link, DWORD v);
|
||||
static const int NOT_A_LINK = 0;
|
||||
|
@ -39,7 +51,14 @@ public:
|
|||
|
||||
int rows;
|
||||
|
||||
// These are called by the platform-specific code.
|
||||
void Paint(int w, int h);
|
||||
void MouseEvent(bool leftDown, double x, double y);
|
||||
void MouseScroll(double x, double y, int delta);
|
||||
void ScrollbarEvent(int newPos);
|
||||
|
||||
void Init(void);
|
||||
void MakeColorTable(const Color *in, float *out);
|
||||
void Printf(bool half, char *fmt, ...);
|
||||
void ClearScreen(void);
|
||||
|
||||
|
|
|
@ -17,29 +17,20 @@
|
|||
#define FREEZE_SUBKEY "SolveSpace"
|
||||
#include "freeze.h"
|
||||
|
||||
#define MIN_COLS 45
|
||||
#define TEXT_HEIGHT 20
|
||||
#define TEXT_WIDTH 9
|
||||
#define TEXT_LEFT_MARGIN 4
|
||||
|
||||
// For the edit controls
|
||||
#define EDIT_WIDTH 220
|
||||
#define EDIT_HEIGHT 21
|
||||
|
||||
// The list representing glyph with ASCII code zero, for bitmap fonts
|
||||
#define BITMAP_GLYPH_BASE 1000
|
||||
|
||||
HINSTANCE Instance;
|
||||
|
||||
HWND TextWnd;
|
||||
HWND TextWndScrollBar;
|
||||
HWND TextEditControl;
|
||||
HGLRC TextGl;
|
||||
int TextEditControlCol, TextEditControlHalfRow;
|
||||
int TextWndScrollPos; // The scrollbar position, in half-row units
|
||||
int TextWndHalfRows; // The height of our window, in half-row units
|
||||
|
||||
HWND GraphicsWnd;
|
||||
HGLRC GraphicsHpgl;
|
||||
HGLRC GraphicsGl;
|
||||
HWND GraphicsEditControl;
|
||||
struct {
|
||||
int x, y;
|
||||
|
@ -53,7 +44,7 @@ HMENU ContextMenu, ContextSubmenu;
|
|||
|
||||
int ClientIsSmallerBy;
|
||||
|
||||
HFONT FixedFont, LinkFont;
|
||||
HFONT FixedFont;
|
||||
|
||||
// The 6-DOF input device.
|
||||
SiHdl SpaceNavigator = SI_NO_HANDLE;
|
||||
|
@ -95,7 +86,8 @@ static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
col = 0;
|
||||
row++;
|
||||
} else {
|
||||
TextOut(hdc, col*TEXT_WIDTH + 10, row*TEXT_HEIGHT + 10,
|
||||
TextOut(hdc, col*SS.TW.CHAR_WIDTH + 10,
|
||||
row*SS.TW.LINE_HEIGHT + 10,
|
||||
&(MessageString[i]), 1);
|
||||
col++;
|
||||
}
|
||||
|
@ -156,14 +148,15 @@ void DoMessageBox(char *str, int rows, int cols, BOOL error)
|
|||
RECT r;
|
||||
GetWindowRect(GraphicsWnd, &r);
|
||||
char *title = error ? "SolveSpace - Error" : "SolveSpace - Message";
|
||||
int width = cols*TEXT_WIDTH + 20, height = rows*TEXT_HEIGHT + 60;
|
||||
int width = cols*SS.TW.CHAR_WIDTH + 20,
|
||||
height = rows*SS.TW.LINE_HEIGHT + 60;
|
||||
MessageWnd = CreateWindowClient(0, "MessageWnd", title,
|
||||
WS_OVERLAPPED | WS_SYSMENU,
|
||||
r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL);
|
||||
|
||||
OkButton = CreateWindowEx(0, WC_BUTTON, "OK",
|
||||
WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE | BS_DEFPUSHBUTTON,
|
||||
(width - 70)/2, rows*TEXT_HEIGHT + 20,
|
||||
(width - 70)/2, rows*SS.TW.LINE_HEIGHT + 20,
|
||||
70, 25, MessageWnd, NULL, Instance, NULL);
|
||||
SendMessage(OkButton, WM_SETFONT, (WPARAM)FixedFont, TRUE);
|
||||
|
||||
|
@ -242,17 +235,16 @@ void SetTimerFor(int milliseconds)
|
|||
SetTimer(GraphicsWnd, 1, milliseconds, TimerCallback);
|
||||
}
|
||||
|
||||
void DrawWithBitmapFont(char *str)
|
||||
static void GetWindowSize(HWND hwnd, int *w, int *h)
|
||||
{
|
||||
// These lists were created in CreateGlContext
|
||||
glListBase(BITMAP_GLYPH_BASE);
|
||||
glCallLists(strlen(str), GL_UNSIGNED_BYTE, str);
|
||||
RECT r;
|
||||
GetClientRect(hwnd, &r);
|
||||
*w = r.right - r.left;
|
||||
*h = r.bottom - r.top;
|
||||
}
|
||||
void GetBitmapFontExtent(char *str, int *w, int *h)
|
||||
void GetGraphicsWindowSize(int *w, int *h)
|
||||
{
|
||||
// Easy since that's a fixed-width font for now.
|
||||
*h = TEXT_HEIGHT;
|
||||
*w = TEXT_WIDTH*strlen(str);
|
||||
GetWindowSize(GraphicsWnd, w, h);
|
||||
}
|
||||
|
||||
void OpenWebsite(char *url) {
|
||||
|
@ -291,143 +283,59 @@ void SetWindowTitle(char *str) {
|
|||
SetWindowText(GraphicsWnd, str);
|
||||
}
|
||||
|
||||
void SetMousePointerToHand(bool yes) {
|
||||
SetCursor(LoadCursor(NULL, yes ? IDC_HAND : IDC_ARROW));
|
||||
}
|
||||
|
||||
static void PaintTextWnd(HDC hdc)
|
||||
{
|
||||
int i;
|
||||
wglMakeCurrent(GetDC(TextWnd), TextGl);
|
||||
|
||||
static BOOL MadeBrushes = FALSE;
|
||||
static COLORREF BgColor[256];
|
||||
static COLORREF FgColor[256];
|
||||
static HBRUSH BgBrush[256];
|
||||
static HBRUSH FillBrush;
|
||||
if(!MadeBrushes) {
|
||||
// Generate the color table.
|
||||
for(i = 0; SS.TW.fgColors[i].c != 0; i++) {
|
||||
int c = SS.TW.fgColors[i].c;
|
||||
if(c < 0 || c > 255) oops();
|
||||
FgColor[c] = SS.TW.fgColors[i].color;
|
||||
}
|
||||
for(i = 0; SS.TW.bgColors[i].c != 0; i++) {
|
||||
int c = SS.TW.bgColors[i].c;
|
||||
if(c < 0 || c > 255) oops();
|
||||
BgColor[c] = SS.TW.bgColors[i].color;
|
||||
BgBrush[c] = CreateSolidBrush(BgColor[c]);
|
||||
}
|
||||
FillBrush = CreateSolidBrush(RGB(0, 0, 0));
|
||||
MadeBrushes = TRUE;
|
||||
}
|
||||
int w, h;
|
||||
GetWindowSize(TextWnd, &w, &h);
|
||||
SS.TW.Paint(w, h);
|
||||
SwapBuffers(GetDC(TextWnd));
|
||||
|
||||
RECT rect;
|
||||
GetClientRect(TextWnd, &rect);
|
||||
// Set up the back-buffer
|
||||
HDC backDc = CreateCompatibleDC(hdc);
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
HBITMAP backBitmap = CreateCompatibleBitmap(hdc, width, height);
|
||||
SelectObject(backDc, backBitmap);
|
||||
// Leave the graphics window context active, except when we're painting
|
||||
// this text window.
|
||||
wglMakeCurrent(GetDC(GraphicsWnd), GraphicsGl);
|
||||
}
|
||||
|
||||
FillRect(backDc, &rect, FillBrush);
|
||||
|
||||
SelectObject(backDc, FixedFont);
|
||||
SetBkColor(backDc, RGB(0, 0, 0));
|
||||
|
||||
int halfRows = height / (TEXT_HEIGHT/2);
|
||||
TextWndHalfRows = halfRows;
|
||||
|
||||
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
|
||||
TextWndScrollPos = min(TextWndScrollPos, bottom - halfRows);
|
||||
TextWndScrollPos = max(TextWndScrollPos, 0);
|
||||
|
||||
// Let's set up the scroll bar first
|
||||
void MoveTextScrollbarTo(int pos, int maxPos, int page)
|
||||
{
|
||||
SCROLLINFO si;
|
||||
memset(&si, 0, sizeof(si));
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_DISABLENOSCROLL | SIF_ALL;
|
||||
si.nMin = 0;
|
||||
si.nMax = SS.TW.top[SS.TW.rows - 1] + 1;
|
||||
si.nPos = TextWndScrollPos;
|
||||
si.nPage = halfRows;
|
||||
si.nMax = maxPos;
|
||||
si.nPos = pos;
|
||||
si.nPage = page;
|
||||
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE);
|
||||
|
||||
int r, c;
|
||||
for(r = 0; r < SS.TW.rows; r++) {
|
||||
int top = SS.TW.top[r];
|
||||
if(top < (TextWndScrollPos-1)) continue;
|
||||
if(top > TextWndScrollPos+halfRows) break;
|
||||
|
||||
for(c = 0; c < min((width/TEXT_WIDTH)+1, SS.TW.MAX_COLS); c++) {
|
||||
int fg = SS.TW.meta[r][c].fg;
|
||||
int bg = SS.TW.meta[r][c].bg;
|
||||
|
||||
SetTextColor(backDc, FgColor[fg]);
|
||||
|
||||
HBRUSH bgb;
|
||||
if(bg & 0x80000000) {
|
||||
bgb = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
||||
SetBkColor(backDc, bg & 0xffffff);
|
||||
} else {
|
||||
bgb = BgBrush[bg];
|
||||
SetBkColor(backDc, BgColor[bg]);
|
||||
}
|
||||
|
||||
if(SS.TW.meta[r][c].link && SS.TW.meta[r][c].link != 'n') {
|
||||
SelectObject(backDc, LinkFont);
|
||||
} else {
|
||||
SelectObject(backDc, FixedFont);
|
||||
}
|
||||
|
||||
int x = TEXT_LEFT_MARGIN + c*TEXT_WIDTH;
|
||||
int y = (top-TextWndScrollPos)*(TEXT_HEIGHT/2);
|
||||
|
||||
RECT a;
|
||||
a.left = x; a.right = x+TEXT_WIDTH;
|
||||
a.top = y; a.bottom = y+TEXT_HEIGHT;
|
||||
FillRect(backDc, &a, bgb);
|
||||
|
||||
TextOut(backDc, x, y+2, (char *)&(SS.TW.text[r][c]), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// And commit the back buffer
|
||||
BitBlt(hdc, 0, 0, width, height, backDc, 0, 0, SRCCOPY);
|
||||
DeleteObject(backBitmap);
|
||||
DeleteDC(backDc);
|
||||
}
|
||||
|
||||
void HandleTextWindowScrollBar(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
int prevPos = TextWndScrollPos;
|
||||
int maxPos, minPos, pos;
|
||||
GetScrollRange(TextWndScrollBar, SB_CTL, &minPos, &maxPos);
|
||||
pos = GetScrollPos(TextWndScrollBar, SB_CTL);
|
||||
|
||||
switch(LOWORD(wParam)) {
|
||||
case SB_LINEUP: TextWndScrollPos--; break;
|
||||
case SB_PAGEUP: TextWndScrollPos -= 4; break;
|
||||
case SB_LINEUP: pos--; break;
|
||||
case SB_PAGEUP: pos -= 4; break;
|
||||
|
||||
case SB_LINEDOWN: TextWndScrollPos++; break;
|
||||
case SB_PAGEDOWN: TextWndScrollPos += 4; break;
|
||||
case SB_LINEDOWN: pos++; break;
|
||||
case SB_PAGEDOWN: pos += 4; break;
|
||||
|
||||
case SB_TOP: TextWndScrollPos = 0; break;
|
||||
case SB_TOP: pos = 0; break;
|
||||
|
||||
case SB_BOTTOM: TextWndScrollPos = SS.TW.rows; break;
|
||||
case SB_BOTTOM: pos = maxPos; break;
|
||||
|
||||
case SB_THUMBTRACK:
|
||||
case SB_THUMBPOSITION: TextWndScrollPos = HIWORD(wParam); break;
|
||||
case SB_THUMBPOSITION: pos = HIWORD(wParam); break;
|
||||
}
|
||||
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
|
||||
TextWndScrollPos = min(TextWndScrollPos, bottom - TextWndHalfRows);
|
||||
TextWndScrollPos = max(TextWndScrollPos, 0);
|
||||
if(prevPos != TextWndScrollPos) {
|
||||
SCROLLINFO si;
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_POS;
|
||||
si.nPos = TextWndScrollPos;
|
||||
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE);
|
||||
|
||||
if(TextEditControlIsVisible()) {
|
||||
int x = TEXT_LEFT_MARGIN + TEXT_WIDTH*TextEditControlCol;
|
||||
int y = (TextEditControlHalfRow - TextWndScrollPos)*(TEXT_HEIGHT/2);
|
||||
MoveWindow(TextEditControl, x, y, EDIT_WIDTH, EDIT_HEIGHT, TRUE);
|
||||
}
|
||||
InvalidateRect(TextWnd, NULL, FALSE);
|
||||
}
|
||||
SS.TW.ScrollbarEvent(pos);
|
||||
}
|
||||
|
||||
static void MouseWheel(int thisDelta) {
|
||||
|
@ -485,9 +393,11 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
break;
|
||||
|
||||
case WM_PAINT: {
|
||||
// Actually paint the text window, with gl.
|
||||
PaintTextWnd(GetDC(TextWnd));
|
||||
// And then just make Windows happy.
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
PaintTextWnd(hdc);
|
||||
EndPaint(hwnd, &ps);
|
||||
break;
|
||||
}
|
||||
|
@ -495,7 +405,7 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
case WM_SIZING: {
|
||||
RECT *r = (RECT *)lParam;
|
||||
int hc = (r->bottom - r->top) - ClientIsSmallerBy;
|
||||
int extra = hc % (TEXT_HEIGHT/2);
|
||||
int extra = hc % (SS.TW.LINE_HEIGHT/2);
|
||||
switch(wParam) {
|
||||
case WMSZ_BOTTOM:
|
||||
case WMSZ_BOTTOMLEFT:
|
||||
|
@ -509,7 +419,8 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
r->top += extra;
|
||||
break;
|
||||
}
|
||||
int tooNarrow = (MIN_COLS*TEXT_WIDTH) - (r->right - r->left);
|
||||
int tooNarrow = (SS.TW.MIN_COLS*SS.TW.CHAR_WIDTH) -
|
||||
(r->right - r->left);
|
||||
if(tooNarrow >= 0) {
|
||||
switch(wParam) {
|
||||
case WMSZ_RIGHT:
|
||||
|
@ -530,57 +441,9 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MOUSEMOVE: {
|
||||
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) {
|
||||
if(msg == WM_MOUSEMOVE) {
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
} else {
|
||||
HideTextEditControl();
|
||||
HideGraphicsEditControl();
|
||||
}
|
||||
break;
|
||||
}
|
||||
GraphicsWindow::Selection ps = SS.GW.hover;
|
||||
SS.GW.hover.Clear();
|
||||
|
||||
int x = LOWORD(lParam);
|
||||
int y = HIWORD(lParam);
|
||||
|
||||
// Find the corresponding character in the text buffer
|
||||
int c = (x / TEXT_WIDTH);
|
||||
int hh = (TEXT_HEIGHT)/2;
|
||||
y += TextWndScrollPos*hh;
|
||||
int r;
|
||||
for(r = 0; r < SS.TW.rows; r++) {
|
||||
if(y >= SS.TW.top[r]*hh && y <= (SS.TW.top[r]+2)*hh) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(r >= SS.TW.rows) {
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
goto done;
|
||||
}
|
||||
|
||||
#define META (SS.TW.meta[r][c])
|
||||
if(msg == WM_MOUSEMOVE) {
|
||||
if(META.link) {
|
||||
SetCursor(LoadCursor(NULL, IDC_HAND));
|
||||
if(META.h) {
|
||||
(META.h)(META.link, META.data);
|
||||
}
|
||||
} else {
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
}
|
||||
} else {
|
||||
if(META.link && META.f) {
|
||||
(META.f)(META.link, META.data);
|
||||
SS.TW.Show();
|
||||
InvalidateGraphics();
|
||||
}
|
||||
}
|
||||
done:
|
||||
if(!ps.Equals(&(SS.GW.hover))) {
|
||||
InvalidateGraphics();
|
||||
}
|
||||
SS.TW.MouseEvent(msg == WM_LBUTTONDOWN, x, y);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -702,9 +565,9 @@ void ShowTextWindow(BOOL visible)
|
|||
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
|
||||
}
|
||||
|
||||
static void CreateGlContext(void)
|
||||
static void CreateGlContext(HWND hwnd, HGLRC *glrc)
|
||||
{
|
||||
HDC hdc = GetDC(GraphicsWnd);
|
||||
HDC hdc = GetDC(hwnd);
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
int pixelFormat;
|
||||
|
@ -726,33 +589,21 @@ static void CreateGlContext(void)
|
|||
|
||||
if(!SetPixelFormat(hdc, pixelFormat, &pfd)) oops();
|
||||
|
||||
GraphicsHpgl = wglCreateContext(hdc);
|
||||
wglMakeCurrent(hdc, GraphicsHpgl);
|
||||
|
||||
// Create a bitmap font in a display list, for DrawWithBitmapFont().
|
||||
SelectObject(hdc, FixedFont);
|
||||
wglUseFontBitmaps(hdc, 0, 255, BITMAP_GLYPH_BASE);
|
||||
*glrc = wglCreateContext(hdc);
|
||||
wglMakeCurrent(hdc, *glrc);
|
||||
}
|
||||
|
||||
void InvalidateGraphics(void)
|
||||
{
|
||||
InvalidateRect(GraphicsWnd, NULL, FALSE);
|
||||
}
|
||||
void GetGraphicsWindowSize(int *w, int *h)
|
||||
{
|
||||
RECT r;
|
||||
GetClientRect(GraphicsWnd, &r);
|
||||
*w = r.right - r.left;
|
||||
*h = r.bottom - r.top;
|
||||
}
|
||||
void PaintGraphics(void)
|
||||
{
|
||||
int w, h;
|
||||
GetGraphicsWindowSize(&w, &h);
|
||||
|
||||
GetWindowSize(GraphicsWnd, &w, &h);
|
||||
SS.GW.Paint(w, h);
|
||||
SwapBuffers(GetDC(GraphicsWnd));
|
||||
}
|
||||
void InvalidateGraphics(void)
|
||||
{
|
||||
InvalidateRect(GraphicsWnd, NULL, FALSE);
|
||||
}
|
||||
|
||||
SDWORD GetMilliseconds(void)
|
||||
{
|
||||
|
@ -778,16 +629,18 @@ void InvalidateText(void)
|
|||
static void ShowEditControl(HWND h, int x, int y, char *s) {
|
||||
MoveWindow(h, x, y, EDIT_WIDTH, EDIT_HEIGHT, TRUE);
|
||||
ShowWindow(h, SW_SHOW);
|
||||
if(s) {
|
||||
SendMessage(h, WM_SETTEXT, 0, (LPARAM)s);
|
||||
SendMessage(h, EM_SETSEL, 0, strlen(s));
|
||||
SetFocus(h);
|
||||
}
|
||||
}
|
||||
void ShowTextEditControl(int hr, int c, char *s)
|
||||
{
|
||||
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return;
|
||||
if(GraphicsEditControlIsVisible()) return;
|
||||
|
||||
int x = TEXT_LEFT_MARGIN + TEXT_WIDTH*c;
|
||||
int y = (hr - TextWndScrollPos)*(TEXT_HEIGHT/2);
|
||||
int x = SS.TW.LEFT_MARGIN + SS.TW.CHAR_WIDTH*c;
|
||||
int y = (hr - SS.TW.scrollPos)*(SS.TW.LINE_HEIGHT/2);
|
||||
TextEditControlCol = c;
|
||||
TextEditControlHalfRow = hr;
|
||||
ShowEditControl(TextEditControl, x, y, s);
|
||||
|
@ -802,7 +655,7 @@ BOOL TextEditControlIsVisible(void)
|
|||
}
|
||||
void ShowGraphicsEditControl(int x, int y, char *s)
|
||||
{
|
||||
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return;
|
||||
if(GraphicsEditControlIsVisible()) return;
|
||||
|
||||
RECT r;
|
||||
GetClientRect(GraphicsWnd, &r);
|
||||
|
@ -836,7 +689,9 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
break;
|
||||
|
||||
case WM_PAINT: {
|
||||
// Actually paint the window, with gl.
|
||||
PaintGraphics();
|
||||
// And make Windows happy.
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
EndPaint(hwnd, &ps);
|
||||
|
@ -1149,14 +1004,11 @@ static void CreateMainWindows(void)
|
|||
50, 50, 900, 600, NULL, top, Instance, NULL);
|
||||
if(!GraphicsWnd) oops();
|
||||
|
||||
CreateGlContext();
|
||||
|
||||
GraphicsEditControl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, "",
|
||||
WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS,
|
||||
50, 50, 100, 21, GraphicsWnd, NULL, Instance, NULL);
|
||||
SendMessage(GraphicsEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE);
|
||||
|
||||
|
||||
// The text window, with a comand line and some textual information
|
||||
// about the sketch.
|
||||
wc.style &= ~CS_DBLCLKS;
|
||||
|
@ -1184,6 +1036,9 @@ static void CreateMainWindows(void)
|
|||
50, 50, 100, 21, TextWnd, NULL, Instance, NULL);
|
||||
SendMessage(TextEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE);
|
||||
|
||||
// Now that all our windows exist, set up gl contexts.
|
||||
CreateGlContext(TextWnd, &TextGl);
|
||||
CreateGlContext(GraphicsWnd, &GraphicsGl);
|
||||
|
||||
RECT r, rc;
|
||||
GetWindowRect(TextWnd, &r);
|
||||
|
@ -1238,16 +1093,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
InitCommonControls();
|
||||
|
||||
// A monospaced font
|
||||
FixedFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
|
||||
FixedFont = CreateFont(SS.TW.CHAR_HEIGHT, SS.TW.CHAR_WIDTH, 0, 0,
|
||||
FW_REGULAR, FALSE,
|
||||
FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||||
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
|
||||
LinkFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
|
||||
TRUE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||||
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
|
||||
if(!FixedFont)
|
||||
FixedFont = (HFONT)GetStockObject(SYSTEM_FONT);
|
||||
if(!LinkFont)
|
||||
LinkFont = (HFONT)GetStockObject(SYSTEM_FONT);
|
||||
|
||||
// Create the root windows: one for control, with text, and one for
|
||||
// the graphics
|
||||
|
|
|
@ -3,6 +3,7 @@ add checked/unchecked checkbox and radio button
|
|||
fix bug with rotation in plane where green line stays displayed
|
||||
lock point where dragged constraint
|
||||
remove toolbar icons for sketch in 3d, add View -> Align to Workplane
|
||||
expose transformed point stuff in library, and email McNeel
|
||||
|
||||
-----
|
||||
rounding, as a special group
|
||||
|
|
Loading…
Reference in New Issue