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
Jonathan Westhues 2010-04-25 23:52:49 -08:00
parent 6750995ef0
commit c4b442f92f
13 changed files with 2591 additions and 242 deletions

View File

@ -94,6 +94,8 @@ $(RES): win32/$(@B).rc icon.ico
toolbar.cpp: $(OBJDIR)/icons.h toolbar.cpp: $(OBJDIR)/icons.h
glhelper.cpp: bitmapfont.table font.table
$(OBJDIR)/icons.h: icons/* png2c.pl $(OBJDIR)/icons.h: icons/* png2c.pl
perl png2c.pl > $(OBJDIR)/icons.h perl png2c.pl > $(OBJDIR)/icons.h

2178
bitmapfont.table Normal file

File diff suppressed because it is too large Load Diff

View File

@ -525,7 +525,7 @@ void GraphicsWindow::Paint(int w, int h) {
if(SS.bgImage.fromFile) { if(SS.bgImage.fromFile) {
// If a background image is loaded, then we draw it now as a texture. // If a background image is loaded, then we draw it now as a texture.
// This handles the resizing for us nicely. // 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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);

View File

@ -215,10 +215,12 @@ void SolveSpace::GenerateAll(int first, int last, bool andFindFree) {
glVertex2d(left, top-height); glVertex2d(left, top-height);
glEnd(); glEnd();
glxCreateBitmapFont();
glColor3d(0, 0, 0); glColor3d(0, 0, 0);
glPushMatrix(); glPushMatrix();
glRasterPos2d(left+8, top-17); glTranslated(left+8, top-20, 0);
DrawWithBitmapFont(msg); glScaled(1, -1, 1);
glxBitmapText(msg, Vector::From(0, 0, 0));
glPopMatrix(); glPopMatrix();
glFlush(); glFlush();
glDrawBuffer(GL_BACK); glDrawBuffer(GL_BACK);

View File

@ -3,6 +3,9 @@
// A public-domain Hershey vector font ("Simplex"). // A public-domain Hershey vector font ("Simplex").
#include "font.table" #include "font.table"
// A bitmap font.
#include "bitmapfont.table"
static bool ColorLocked; static bool ColorLocked;
static bool DepthOffsetLocked; 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);
}

View File

@ -131,6 +131,7 @@ BOOL GraphicsEditControlIsVisible(void);
void ShowTextEditControl(int hr, int c, char *s); void ShowTextEditControl(int hr, int c, char *s);
void HideTextEditControl(void); void HideTextEditControl(void);
BOOL TextEditControlIsVisible(void); BOOL TextEditControlIsVisible(void);
void MoveTextScrollbarTo(int pos, int maxPos, int page);
#define CONTEXT_SUBMENU (-1) #define CONTEXT_SUBMENU (-1)
#define CONTEXT_SEPARATOR (-2) #define CONTEXT_SEPARATOR (-2)
@ -152,13 +153,11 @@ void dbp(char *str, ...);
CO((tri).a), CO((tri).b), CO((tri).c)) CO((tri).a), CO((tri).b), CO((tri).c))
void SetWindowTitle(char *str); void SetWindowTitle(char *str);
void SetMousePointerToHand(bool yes);
void DoMessageBox(char *str, int rows, int cols, BOOL error); void DoMessageBox(char *str, int rows, int cols, BOOL error);
void SetTimerFor(int milliseconds); void SetTimerFor(int milliseconds);
void ExitNow(void); void ExitNow(void);
void DrawWithBitmapFont(char *str);
void GetBitmapFontExtent(char *str, int *w, int *h);
void CnfFreezeString(char *str, char *name); void CnfFreezeString(char *str, char *name);
void CnfFreezeDWORD(DWORD v, char *name); void CnfFreezeDWORD(DWORD v, char *name);
void CnfFreezeFloat(float v, char *name); void CnfFreezeFloat(float v, char *name);
@ -222,6 +221,11 @@ void glxColorRGB(DWORD rgb);
void glxColorRGBa(DWORD rgb, double a); void glxColorRGBa(DWORD rgb, double a);
void glxDepthRangeOffset(int units); void glxDepthRangeOffset(int units);
void glxDepthRangeLockToFront(bool yes); 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])) #define arraylen(x) (sizeof((x))/sizeof((x)[0]))

View File

@ -22,13 +22,28 @@ const TextWindow::Color TextWindow::bgColors[] = {
{ 0, 0 }, { 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) { void TextWindow::Init(void) {
ClearSuper(); ClearSuper();
} }
void TextWindow::ClearSuper(void) { void TextWindow::ClearSuper(void) {
HideTextEditControl(); HideTextEditControl();
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
MakeColorTable(fgColors, fgColorTable);
MakeColorTable(bgColors, bgColorTable);
ClearScreen(); ClearScreen();
Show(); Show();
} }
@ -244,3 +259,170 @@ void TextWindow::Show(void) {
InvalidateText(); 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();
}
}

View File

@ -209,6 +209,7 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
if(paint) { if(paint) {
// Do this last so that nothing can draw over it. // Do this last so that nothing can draw over it.
if(toolTip.show) { if(toolTip.show) {
glxCreateBitmapFont();
char str[1024]; char str[1024];
if(strlen(toolTip.str) >= 200) oops(); if(strlen(toolTip.str) >= 200) oops();
strcpy(str, toolTip.str); strcpy(str, toolTip.str);
@ -229,10 +230,8 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
} }
} }
int tw, th; int tw = strlen(str)*SS.TW.CHAR_WIDTH + 10,
GetBitmapFontExtent(str, &tw, &th); th = SS.TW.LINE_HEIGHT + 2;
tw += 10;
th += 2;
double ox = toolbarMouseX + 3, oy = toolbarMouseY + 3; double ox = toolbarMouseX + 3, oy = toolbarMouseY + 3;
glLineWidth(1); glLineWidth(1);
@ -253,8 +252,9 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
glColor4d(0, 0, 0, 1); glColor4d(0, 0, 0, 1);
glPushMatrix(); glPushMatrix();
glRasterPos2d(ox+6, oy+6); glTranslated(ox+5, oy+3, 0);
DrawWithBitmapFont(str); glScaled(1, -1, 1);
glxBitmapText(str, Vector::From(0, 0, 0));
glPopMatrix(); glPopMatrix();
} }
glxDepthRangeLockToFront(false); glxDepthRangeLockToFront(false);

4
tools/Makefile Normal file
View File

@ -0,0 +1,4 @@
all:
cl ttf2c.cpp user32.lib gdi32.lib comctl32.lib
ttf2c.exe > ..\bitmapfont.table

52
tools/ttf2c.cpp Normal file
View File

@ -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
View File

@ -5,6 +5,7 @@
class TextWindow { class TextWindow {
public: public:
static const int MAX_COLS = 100; static const int MAX_COLS = 100;
static const int MIN_COLS = 45;
static const int MAX_ROWS = 2000; static const int MAX_ROWS = 2000;
#ifndef RGB #ifndef RGB
@ -24,6 +25,17 @@ public:
static const Color fgColors[]; static const Color fgColors[];
static const Color bgColors[]; 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]; BYTE text[MAX_ROWS][MAX_COLS];
typedef void LinkFunction(int link, DWORD v); typedef void LinkFunction(int link, DWORD v);
static const int NOT_A_LINK = 0; static const int NOT_A_LINK = 0;
@ -39,7 +51,14 @@ public:
int rows; 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 Init(void);
void MakeColorTable(const Color *in, float *out);
void Printf(bool half, char *fmt, ...); void Printf(bool half, char *fmt, ...);
void ClearScreen(void); void ClearScreen(void);

View File

@ -17,29 +17,20 @@
#define FREEZE_SUBKEY "SolveSpace" #define FREEZE_SUBKEY "SolveSpace"
#include "freeze.h" #include "freeze.h"
#define MIN_COLS 45
#define TEXT_HEIGHT 20
#define TEXT_WIDTH 9
#define TEXT_LEFT_MARGIN 4
// For the edit controls // For the edit controls
#define EDIT_WIDTH 220 #define EDIT_WIDTH 220
#define EDIT_HEIGHT 21 #define EDIT_HEIGHT 21
// The list representing glyph with ASCII code zero, for bitmap fonts
#define BITMAP_GLYPH_BASE 1000
HINSTANCE Instance; HINSTANCE Instance;
HWND TextWnd; HWND TextWnd;
HWND TextWndScrollBar; HWND TextWndScrollBar;
HWND TextEditControl; HWND TextEditControl;
HGLRC TextGl;
int TextEditControlCol, TextEditControlHalfRow; 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; HWND GraphicsWnd;
HGLRC GraphicsHpgl; HGLRC GraphicsGl;
HWND GraphicsEditControl; HWND GraphicsEditControl;
struct { struct {
int x, y; int x, y;
@ -53,7 +44,7 @@ HMENU ContextMenu, ContextSubmenu;
int ClientIsSmallerBy; int ClientIsSmallerBy;
HFONT FixedFont, LinkFont; HFONT FixedFont;
// The 6-DOF input device. // The 6-DOF input device.
SiHdl SpaceNavigator = SI_NO_HANDLE; SiHdl SpaceNavigator = SI_NO_HANDLE;
@ -95,7 +86,8 @@ static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
col = 0; col = 0;
row++; row++;
} else { } 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); &(MessageString[i]), 1);
col++; col++;
} }
@ -156,14 +148,15 @@ void DoMessageBox(char *str, int rows, int cols, BOOL error)
RECT r; RECT r;
GetWindowRect(GraphicsWnd, &r); GetWindowRect(GraphicsWnd, &r);
char *title = error ? "SolveSpace - Error" : "SolveSpace - Message"; 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, MessageWnd = CreateWindowClient(0, "MessageWnd", title,
WS_OVERLAPPED | WS_SYSMENU, WS_OVERLAPPED | WS_SYSMENU,
r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL); r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL);
OkButton = CreateWindowEx(0, WC_BUTTON, "OK", OkButton = CreateWindowEx(0, WC_BUTTON, "OK",
WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE | BS_DEFPUSHBUTTON, 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); 70, 25, MessageWnd, NULL, Instance, NULL);
SendMessage(OkButton, WM_SETFONT, (WPARAM)FixedFont, TRUE); SendMessage(OkButton, WM_SETFONT, (WPARAM)FixedFont, TRUE);
@ -242,17 +235,16 @@ void SetTimerFor(int milliseconds)
SetTimer(GraphicsWnd, 1, milliseconds, TimerCallback); SetTimer(GraphicsWnd, 1, milliseconds, TimerCallback);
} }
void DrawWithBitmapFont(char *str) static void GetWindowSize(HWND hwnd, int *w, int *h)
{ {
// These lists were created in CreateGlContext RECT r;
glListBase(BITMAP_GLYPH_BASE); GetClientRect(hwnd, &r);
glCallLists(strlen(str), GL_UNSIGNED_BYTE, str); *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. GetWindowSize(GraphicsWnd, w, h);
*h = TEXT_HEIGHT;
*w = TEXT_WIDTH*strlen(str);
} }
void OpenWebsite(char *url) { void OpenWebsite(char *url) {
@ -291,143 +283,59 @@ void SetWindowTitle(char *str) {
SetWindowText(GraphicsWnd, str); SetWindowText(GraphicsWnd, str);
} }
void SetMousePointerToHand(bool yes) {
SetCursor(LoadCursor(NULL, yes ? IDC_HAND : IDC_ARROW));
}
static void PaintTextWnd(HDC hdc) static void PaintTextWnd(HDC hdc)
{ {
int i; wglMakeCurrent(GetDC(TextWnd), TextGl);
static BOOL MadeBrushes = FALSE; int w, h;
static COLORREF BgColor[256]; GetWindowSize(TextWnd, &w, &h);
static COLORREF FgColor[256]; SS.TW.Paint(w, h);
static HBRUSH BgBrush[256]; SwapBuffers(GetDC(TextWnd));
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;
}
RECT rect; // Leave the graphics window context active, except when we're painting
GetClientRect(TextWnd, &rect); // this text window.
// Set up the back-buffer wglMakeCurrent(GetDC(GraphicsWnd), GraphicsGl);
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);
FillRect(backDc, &rect, FillBrush); void MoveTextScrollbarTo(int pos, int maxPos, int page)
{
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
SCROLLINFO si; SCROLLINFO si;
memset(&si, 0, sizeof(si)); memset(&si, 0, sizeof(si));
si.cbSize = sizeof(si); si.cbSize = sizeof(si);
si.fMask = SIF_DISABLENOSCROLL | SIF_ALL; si.fMask = SIF_DISABLENOSCROLL | SIF_ALL;
si.nMin = 0; si.nMin = 0;
si.nMax = SS.TW.top[SS.TW.rows - 1] + 1; si.nMax = maxPos;
si.nPos = TextWndScrollPos; si.nPos = pos;
si.nPage = halfRows; si.nPage = page;
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE); 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) 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)) { switch(LOWORD(wParam)) {
case SB_LINEUP: TextWndScrollPos--; break; case SB_LINEUP: pos--; break;
case SB_PAGEUP: TextWndScrollPos -= 4; break; case SB_PAGEUP: pos -= 4; break;
case SB_LINEDOWN: TextWndScrollPos++; break; case SB_LINEDOWN: pos++; break;
case SB_PAGEDOWN: TextWndScrollPos += 4; 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_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()) { SS.TW.ScrollbarEvent(pos);
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);
}
} }
static void MouseWheel(int thisDelta) { static void MouseWheel(int thisDelta) {
@ -485,9 +393,11 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
break; break;
case WM_PAINT: { case WM_PAINT: {
// Actually paint the text window, with gl.
PaintTextWnd(GetDC(TextWnd));
// And then just make Windows happy.
PAINTSTRUCT ps; PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); HDC hdc = BeginPaint(hwnd, &ps);
PaintTextWnd(hdc);
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
break; break;
} }
@ -495,7 +405,7 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_SIZING: { case WM_SIZING: {
RECT *r = (RECT *)lParam; RECT *r = (RECT *)lParam;
int hc = (r->bottom - r->top) - ClientIsSmallerBy; int hc = (r->bottom - r->top) - ClientIsSmallerBy;
int extra = hc % (TEXT_HEIGHT/2); int extra = hc % (SS.TW.LINE_HEIGHT/2);
switch(wParam) { switch(wParam) {
case WMSZ_BOTTOM: case WMSZ_BOTTOM:
case WMSZ_BOTTOMLEFT: case WMSZ_BOTTOMLEFT:
@ -509,7 +419,8 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
r->top += extra; r->top += extra;
break; 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) { if(tooNarrow >= 0) {
switch(wParam) { switch(wParam) {
case WMSZ_RIGHT: case WMSZ_RIGHT:
@ -530,57 +441,9 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_MOUSEMOVE: { 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 x = LOWORD(lParam);
int y = HIWORD(lParam); int y = HIWORD(lParam);
SS.TW.MouseEvent(msg == WM_LBUTTONDOWN, x, y);
// 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();
}
break; break;
} }
@ -702,9 +565,9 @@ void ShowTextWindow(BOOL visible)
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE); 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; PIXELFORMATDESCRIPTOR pfd;
int pixelFormat; int pixelFormat;
@ -726,33 +589,21 @@ static void CreateGlContext(void)
if(!SetPixelFormat(hdc, pixelFormat, &pfd)) oops(); if(!SetPixelFormat(hdc, pixelFormat, &pfd)) oops();
GraphicsHpgl = wglCreateContext(hdc); *glrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, GraphicsHpgl); wglMakeCurrent(hdc, *glrc);
// Create a bitmap font in a display list, for DrawWithBitmapFont().
SelectObject(hdc, FixedFont);
wglUseFontBitmaps(hdc, 0, 255, BITMAP_GLYPH_BASE);
} }
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) void PaintGraphics(void)
{ {
int w, h; int w, h;
GetGraphicsWindowSize(&w, &h); GetWindowSize(GraphicsWnd, &w, &h);
SS.GW.Paint(w, h); SS.GW.Paint(w, h);
SwapBuffers(GetDC(GraphicsWnd)); SwapBuffers(GetDC(GraphicsWnd));
} }
void InvalidateGraphics(void)
{
InvalidateRect(GraphicsWnd, NULL, FALSE);
}
SDWORD GetMilliseconds(void) SDWORD GetMilliseconds(void)
{ {
@ -778,16 +629,18 @@ void InvalidateText(void)
static void ShowEditControl(HWND h, int x, int y, char *s) { static void ShowEditControl(HWND h, int x, int y, char *s) {
MoveWindow(h, x, y, EDIT_WIDTH, EDIT_HEIGHT, TRUE); MoveWindow(h, x, y, EDIT_WIDTH, EDIT_HEIGHT, TRUE);
ShowWindow(h, SW_SHOW); ShowWindow(h, SW_SHOW);
if(s) {
SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); SendMessage(h, WM_SETTEXT, 0, (LPARAM)s);
SendMessage(h, EM_SETSEL, 0, strlen(s)); SendMessage(h, EM_SETSEL, 0, strlen(s));
SetFocus(h); SetFocus(h);
}
} }
void ShowTextEditControl(int hr, int c, char *s) void ShowTextEditControl(int hr, int c, char *s)
{ {
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return; if(GraphicsEditControlIsVisible()) return;
int x = TEXT_LEFT_MARGIN + TEXT_WIDTH*c; int x = SS.TW.LEFT_MARGIN + SS.TW.CHAR_WIDTH*c;
int y = (hr - TextWndScrollPos)*(TEXT_HEIGHT/2); int y = (hr - SS.TW.scrollPos)*(SS.TW.LINE_HEIGHT/2);
TextEditControlCol = c; TextEditControlCol = c;
TextEditControlHalfRow = hr; TextEditControlHalfRow = hr;
ShowEditControl(TextEditControl, x, y, s); ShowEditControl(TextEditControl, x, y, s);
@ -802,7 +655,7 @@ BOOL TextEditControlIsVisible(void)
} }
void ShowGraphicsEditControl(int x, int y, char *s) void ShowGraphicsEditControl(int x, int y, char *s)
{ {
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return; if(GraphicsEditControlIsVisible()) return;
RECT r; RECT r;
GetClientRect(GraphicsWnd, &r); GetClientRect(GraphicsWnd, &r);
@ -836,7 +689,9 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
break; break;
case WM_PAINT: { case WM_PAINT: {
// Actually paint the window, with gl.
PaintGraphics(); PaintGraphics();
// And make Windows happy.
PAINTSTRUCT ps; PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); HDC hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps); EndPaint(hwnd, &ps);
@ -1149,14 +1004,11 @@ static void CreateMainWindows(void)
50, 50, 900, 600, NULL, top, Instance, NULL); 50, 50, 900, 600, NULL, top, Instance, NULL);
if(!GraphicsWnd) oops(); if(!GraphicsWnd) oops();
CreateGlContext();
GraphicsEditControl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, "", GraphicsEditControl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, "",
WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS, WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS,
50, 50, 100, 21, GraphicsWnd, NULL, Instance, NULL); 50, 50, 100, 21, GraphicsWnd, NULL, Instance, NULL);
SendMessage(GraphicsEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE); SendMessage(GraphicsEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE);
// The text window, with a comand line and some textual information // The text window, with a comand line and some textual information
// about the sketch. // about the sketch.
wc.style &= ~CS_DBLCLKS; wc.style &= ~CS_DBLCLKS;
@ -1184,6 +1036,9 @@ static void CreateMainWindows(void)
50, 50, 100, 21, TextWnd, NULL, Instance, NULL); 50, 50, 100, 21, TextWnd, NULL, Instance, NULL);
SendMessage(TextEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE); 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; RECT r, rc;
GetWindowRect(TextWnd, &r); GetWindowRect(TextWnd, &r);
@ -1238,16 +1093,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
InitCommonControls(); InitCommonControls();
// A monospaced font // 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, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console"); 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) if(!FixedFont)
FixedFont = (HFONT)GetStockObject(SYSTEM_FONT); FixedFont = (HFONT)GetStockObject(SYSTEM_FONT);
if(!LinkFont)
LinkFont = (HFONT)GetStockObject(SYSTEM_FONT);
// Create the root windows: one for control, with text, and one for // Create the root windows: one for control, with text, and one for
// the graphics // the graphics

View File

@ -3,6 +3,7 @@ add checked/unchecked checkbox and radio button
fix bug with rotation in plane where green line stays displayed fix bug with rotation in plane where green line stays displayed
lock point where dragged constraint lock point where dragged constraint
remove toolbar icons for sketch in 3d, add View -> Align to Workplane 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 rounding, as a special group