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

@ -93,7 +93,9 @@ $(RES): win32/$(@B).rc icon.ico
mv win32/$(@B).res $(OBJDIR)/$(@B).res
toolbar.cpp: $(OBJDIR)/icons.h
glhelper.cpp: bitmapfont.table font.table
$(OBJDIR)/icons.h: icons/* png2c.pl
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 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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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]))

View File

@ -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();
}
}

View File

@ -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);

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 {
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;
@ -38,8 +50,15 @@ public:
int top[MAX_ROWS]; // in half-line units, or -1 for unused
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);

View File

@ -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,8 +86,9 @@ static LRESULT CALLBACK MessageProc(HWND hwnd, UINT msg, WPARAM wParam,
col = 0;
row++;
} else {
TextOut(hdc, col*TEXT_WIDTH + 10, row*TEXT_HEIGHT + 10,
&(MessageString[i]), 1);
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;
}
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);
case SB_THUMBPOSITION: pos = HIWORD(wParam); break;
}
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)
{
HDC hdc = GetDC(GraphicsWnd);
static void CreateGlContext(HWND hwnd, HGLRC *glrc)
{
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);
SendMessage(h, WM_SETTEXT, 0, (LPARAM)s);
SendMessage(h, EM_SETSEL, 0, strlen(s));
SetFocus(h);
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

View File

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