2008-03-25 10:02:13 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <commctrl.h>
|
2008-04-18 11:11:48 +00:00
|
|
|
#include <commdlg.h>
|
2008-03-27 09:53:51 +00:00
|
|
|
#include <gl/gl.h>
|
|
|
|
#include <gl/glu.h>
|
2008-03-25 10:02:13 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2008-03-26 09:18:12 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
|
|
|
#define FREEZE_SUBKEY "SolveSpace"
|
|
|
|
#include "freeze.h"
|
|
|
|
|
2008-04-27 09:03:01 +00:00
|
|
|
#define MIN_COLS 45
|
2008-04-28 07:18:39 +00:00
|
|
|
#define TEXT_HEIGHT 20
|
2008-04-22 10:53:42 +00:00
|
|
|
#define TEXT_WIDTH 9
|
2008-05-27 06:36:59 +00:00
|
|
|
#define TEXT_LEFT_MARGIN 4
|
|
|
|
|
|
|
|
// For the edit controls
|
|
|
|
#define EDIT_WIDTH 220
|
|
|
|
#define EDIT_HEIGHT 21
|
2008-03-25 10:02:13 +00:00
|
|
|
|
|
|
|
HINSTANCE Instance;
|
|
|
|
|
2008-04-01 10:48:44 +00:00
|
|
|
HWND TextWnd;
|
2008-03-25 10:02:13 +00:00
|
|
|
HWND TextWndScrollBar;
|
2008-05-27 06:36:59 +00:00
|
|
|
HWND TextEditControl;
|
|
|
|
int TextEditControlCol, TextEditControlHalfRow;
|
2008-04-28 07:18:39 +00:00
|
|
|
int TextWndScrollPos; // The scrollbar position, in half-row units
|
|
|
|
int TextWndHalfRows; // The height of our window, in half-row units
|
2008-03-26 09:18:12 +00:00
|
|
|
|
2008-04-01 10:48:44 +00:00
|
|
|
HWND GraphicsWnd;
|
2008-05-16 04:54:47 +00:00
|
|
|
HGLRC GraphicsHpgl;
|
2008-04-21 10:12:04 +00:00
|
|
|
HWND GraphicsEditControl;
|
2008-04-01 10:48:44 +00:00
|
|
|
struct {
|
|
|
|
int x, y;
|
|
|
|
} LastMousePos;
|
2008-03-25 10:02:13 +00:00
|
|
|
|
2008-05-28 10:10:31 +00:00
|
|
|
char RecentFile[MAX_RECENT][MAX_PATH];
|
|
|
|
HMENU SubMenus[100];
|
|
|
|
HMENU RecentOpenMenu, RecentImportMenu;
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
int ClientIsSmallerBy;
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
HFONT FixedFont, LinkFont;
|
2008-03-25 10:02:13 +00:00
|
|
|
|
|
|
|
void dbp(char *str, ...)
|
|
|
|
{
|
|
|
|
va_list f;
|
2008-04-21 08:16:38 +00:00
|
|
|
static char buf[1024*50];
|
2008-03-25 10:02:13 +00:00
|
|
|
va_start(f, str);
|
|
|
|
vsprintf(buf, str, f);
|
|
|
|
OutputDebugString(buf);
|
2008-04-21 08:16:38 +00:00
|
|
|
va_end(f);
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
void Error(char *str, ...)
|
|
|
|
{
|
|
|
|
va_list f;
|
|
|
|
char buf[1024];
|
|
|
|
va_start(f, str);
|
|
|
|
vsprintf(buf, str, f);
|
2008-04-21 08:16:38 +00:00
|
|
|
va_end(f);
|
2008-04-12 15:17:58 +00:00
|
|
|
|
2008-06-25 05:14:49 +00:00
|
|
|
EnableWindow(GraphicsWnd, FALSE);
|
|
|
|
EnableWindow(TextWnd, FALSE);
|
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
HWND h = GetForegroundWindow();
|
|
|
|
MessageBox(h, buf, "SolveSpace Error", MB_OK | MB_ICONERROR);
|
2008-06-25 05:14:49 +00:00
|
|
|
|
|
|
|
EnableWindow(TextWnd, TRUE);
|
|
|
|
EnableWindow(GraphicsWnd, TRUE);
|
|
|
|
SetForegroundWindow(GraphicsWnd);
|
2008-04-12 15:17:58 +00:00
|
|
|
}
|
|
|
|
|
2008-06-03 18:48:47 +00:00
|
|
|
void ExitNow(void) {
|
|
|
|
PostQuitMessage(0);
|
|
|
|
}
|
|
|
|
|
2008-06-11 04:22:52 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Helpers so that we can read/write registry keys from the platform-
|
|
|
|
// independent code.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CnfFreezeString(char *str, char *name)
|
|
|
|
{ FreezeStringF(str, FREEZE_SUBKEY, name); }
|
|
|
|
|
|
|
|
void CnfFreezeDWORD(DWORD v, char *name)
|
|
|
|
{ FreezeDWORDF(v, FREEZE_SUBKEY, name); }
|
|
|
|
|
2008-07-08 07:41:29 +00:00
|
|
|
void CnfFreezeFloat(float v, char *name)
|
|
|
|
{ FreezeDWORDF(*((DWORD *)&v), FREEZE_SUBKEY, name); }
|
|
|
|
|
2008-06-11 04:22:52 +00:00
|
|
|
void CnfThawString(char *str, int maxLen, char *name)
|
|
|
|
{ ThawStringF(str, maxLen, FREEZE_SUBKEY, name); }
|
|
|
|
|
|
|
|
DWORD CnfThawDWORD(DWORD v, char *name)
|
|
|
|
{ return ThawDWORDF(v, FREEZE_SUBKEY, name); }
|
|
|
|
|
2008-07-08 07:41:29 +00:00
|
|
|
float CnfThawFloat(float v, char *name) {
|
|
|
|
DWORD d = ThawDWORDF(*((DWORD *)&v), FREEZE_SUBKEY, name);
|
|
|
|
return *((float *)&d);
|
|
|
|
}
|
|
|
|
|
2008-07-08 08:02:22 +00:00
|
|
|
void SetWindowTitle(char *str) {
|
|
|
|
SetWindowText(GraphicsWnd, str);
|
|
|
|
}
|
|
|
|
|
2008-06-11 04:22:52 +00:00
|
|
|
|
2008-04-13 14:28:35 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// A separate heap, on which we allocate expressions. Maybe a bit faster,
|
|
|
|
// since no fragmentation issues whatsoever, and it also makes it possible
|
|
|
|
// to be sloppy with our memory management, and just free everything at once
|
|
|
|
// at the end.
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-05-07 04:17:29 +00:00
|
|
|
static HANDLE Temp;
|
2008-04-25 10:11:29 +00:00
|
|
|
void *AllocTemporary(int n)
|
2008-04-13 14:28:35 +00:00
|
|
|
{
|
2008-05-07 04:17:29 +00:00
|
|
|
void *v = HeapAlloc(Temp, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
|
2008-04-13 14:28:35 +00:00
|
|
|
if(!v) oops();
|
|
|
|
return v;
|
|
|
|
}
|
2008-04-25 10:11:29 +00:00
|
|
|
void FreeAllTemporary(void)
|
2008-04-13 14:28:35 +00:00
|
|
|
{
|
2008-05-07 04:17:29 +00:00
|
|
|
if(Temp) HeapDestroy(Temp);
|
|
|
|
Temp = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
|
|
|
// This is a good place to validate, because it gets called fairly
|
|
|
|
// often.
|
|
|
|
vl();
|
2008-04-13 14:28:35 +00:00
|
|
|
}
|
|
|
|
|
2008-05-07 04:17:29 +00:00
|
|
|
static HANDLE Perm;
|
|
|
|
void *MemRealloc(void *p, int n) {
|
|
|
|
if(!p) {
|
|
|
|
return MemAlloc(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
p = HeapReAlloc(Perm, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, p, n);
|
|
|
|
if(!p) oops();
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
void *MemAlloc(int n) {
|
|
|
|
void *p = HeapAlloc(Perm, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
|
|
|
|
if(!p) oops();
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
void MemFree(void *p) {
|
|
|
|
HeapFree(Perm, HEAP_NO_SERIALIZE, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void vl(void) {
|
|
|
|
if(!HeapValidate(Temp, HEAP_NO_SERIALIZE, NULL)) oops();
|
|
|
|
if(!HeapValidate(Perm, HEAP_NO_SERIALIZE, NULL)) oops();
|
|
|
|
}
|
2008-04-18 07:06:37 +00:00
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
static void PaintTextWnd(HDC hdc)
|
|
|
|
{
|
2008-04-25 08:26:15 +00:00
|
|
|
int i;
|
2008-04-27 09:03:01 +00:00
|
|
|
|
|
|
|
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.
|
2008-04-28 07:18:39 +00:00
|
|
|
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;
|
2008-04-27 09:03:01 +00:00
|
|
|
if(c < 0 || c > 255) oops();
|
2008-04-28 07:18:39 +00:00
|
|
|
BgColor[c] = SS.TW.bgColors[i].color;
|
2008-04-27 09:03:01 +00:00
|
|
|
BgBrush[c] = CreateSolidBrush(BgColor[c]);
|
|
|
|
}
|
2008-04-28 07:18:39 +00:00
|
|
|
FillBrush = CreateSolidBrush(RGB(0, 0, 0));
|
2008-04-27 09:03:01 +00:00
|
|
|
MadeBrushes = TRUE;
|
2008-04-25 08:26:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
RECT rect;
|
|
|
|
GetClientRect(TextWnd, &rect);
|
2008-03-26 09:18:12 +00:00
|
|
|
// 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);
|
2008-03-25 10:02:13 +00:00
|
|
|
|
2008-04-27 09:03:01 +00:00
|
|
|
FillRect(backDc, &rect, FillBrush);
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
SelectObject(backDc, FixedFont);
|
2008-04-28 07:18:39 +00:00
|
|
|
SetBkColor(backDc, RGB(0, 0, 0));
|
2008-03-26 09:18:12 +00:00
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
int halfRows = height / (TEXT_HEIGHT/2);
|
|
|
|
TextWndHalfRows = halfRows;
|
2008-03-25 10:02:13 +00:00
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
|
|
|
|
TextWndScrollPos = min(TextWndScrollPos, bottom - halfRows);
|
2008-04-09 09:35:09 +00:00
|
|
|
TextWndScrollPos = max(TextWndScrollPos, 0);
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
// Let's set up the scroll bar first
|
|
|
|
SCROLLINFO si;
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
si.cbSize = sizeof(si);
|
|
|
|
si.fMask = SIF_DISABLENOSCROLL | SIF_ALL;
|
|
|
|
si.nMin = 0;
|
2008-04-28 07:18:39 +00:00
|
|
|
si.nMax = SS.TW.top[SS.TW.rows - 1] + 1;
|
2008-03-25 10:02:13 +00:00
|
|
|
si.nPos = TextWndScrollPos;
|
2008-04-28 07:18:39 +00:00
|
|
|
si.nPage = halfRows;
|
2008-03-25 10:02:13 +00:00
|
|
|
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE);
|
|
|
|
|
|
|
|
int r, c;
|
2008-04-28 07:18:39 +00:00
|
|
|
for(r = 0; r < SS.TW.rows; r++) {
|
|
|
|
int top = SS.TW.top[r];
|
|
|
|
if(top < (TextWndScrollPos-1)) continue;
|
|
|
|
if(top > TextWndScrollPos+halfRows) break;
|
2008-03-25 10:02:13 +00:00
|
|
|
|
2008-04-27 09:03:01 +00:00
|
|
|
for(c = 0; c < min((width/TEXT_WIDTH)+1, SS.TW.MAX_COLS); c++) {
|
2008-04-28 07:18:39 +00:00
|
|
|
int fg = SS.TW.meta[r][c].fg;
|
|
|
|
int bg = SS.TW.meta[r][c].bg;
|
2008-05-30 06:09:41 +00:00
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
SetTextColor(backDc, FgColor[fg]);
|
2008-03-28 10:00:37 +00:00
|
|
|
|
2008-05-30 06:09:41 +00:00
|
|
|
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') {
|
2008-03-28 10:00:37 +00:00
|
|
|
SelectObject(backDc, LinkFont);
|
|
|
|
} else {
|
|
|
|
SelectObject(backDc, FixedFont);
|
|
|
|
}
|
2008-04-13 14:28:35 +00:00
|
|
|
|
2008-05-27 06:36:59 +00:00
|
|
|
int x = TEXT_LEFT_MARGIN + c*TEXT_WIDTH;
|
2008-04-28 07:18:39 +00:00
|
|
|
int y = (top-TextWndScrollPos)*(TEXT_HEIGHT/2);
|
2008-04-13 14:28:35 +00:00
|
|
|
|
|
|
|
RECT a;
|
|
|
|
a.left = x; a.right = x+TEXT_WIDTH;
|
|
|
|
a.top = y; a.bottom = y+TEXT_HEIGHT;
|
2008-05-30 06:09:41 +00:00
|
|
|
FillRect(backDc, &a, bgb);
|
2008-04-13 14:28:35 +00:00
|
|
|
|
2008-04-28 07:18:39 +00:00
|
|
|
TextOut(backDc, x, y+2, (char *)&(SS.TW.text[r][c]), 1);
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-26 09:18:12 +00:00
|
|
|
// 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;
|
|
|
|
switch(LOWORD(wParam)) {
|
2008-03-28 10:00:37 +00:00
|
|
|
case SB_LINEUP: TextWndScrollPos--; break;
|
|
|
|
case SB_PAGEUP: TextWndScrollPos -= 4; break;
|
2008-03-26 09:18:12 +00:00
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
case SB_LINEDOWN: TextWndScrollPos++; break;
|
|
|
|
case SB_PAGEDOWN: TextWndScrollPos += 4; break;
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
case SB_TOP: TextWndScrollPos = 0; break;
|
|
|
|
|
|
|
|
case SB_BOTTOM: TextWndScrollPos = SS.TW.rows; break;
|
|
|
|
|
|
|
|
case SB_THUMBTRACK:
|
|
|
|
case SB_THUMBPOSITION: TextWndScrollPos = HIWORD(wParam); break;
|
|
|
|
}
|
2008-04-28 07:18:39 +00:00
|
|
|
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
|
|
|
|
TextWndScrollPos = min(TextWndScrollPos, bottom - TextWndHalfRows);
|
|
|
|
TextWndScrollPos = max(TextWndScrollPos, 0);
|
2008-03-26 09:18:12 +00:00
|
|
|
if(prevPos != TextWndScrollPos) {
|
|
|
|
SCROLLINFO si;
|
|
|
|
si.cbSize = sizeof(si);
|
|
|
|
si.fMask = SIF_POS;
|
|
|
|
si.nPos = TextWndScrollPos;
|
|
|
|
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE);
|
|
|
|
|
2008-05-27 06:36:59 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-03-26 09:18:12 +00:00
|
|
|
InvalidateRect(TextWnd, NULL, FALSE);
|
|
|
|
}
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (msg) {
|
2008-04-27 09:31:56 +00:00
|
|
|
case WM_ERASEBKGND:
|
|
|
|
break;
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
case WM_CLOSE:
|
|
|
|
case WM_DESTROY:
|
2008-06-03 18:28:41 +00:00
|
|
|
SolveSpace::MenuFile(GraphicsWindow::MNU_EXIT);
|
2008-03-25 10:02:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_PAINT: {
|
|
|
|
PAINTSTRUCT ps;
|
|
|
|
HDC hdc = BeginPaint(hwnd, &ps);
|
|
|
|
PaintTextWnd(hdc);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_SIZING: {
|
|
|
|
RECT *r = (RECT *)lParam;
|
|
|
|
int hc = (r->bottom - r->top) - ClientIsSmallerBy;
|
2008-04-28 07:18:39 +00:00
|
|
|
int extra = hc % (TEXT_HEIGHT/2);
|
2008-03-25 10:02:13 +00:00
|
|
|
switch(wParam) {
|
|
|
|
case WMSZ_BOTTOM:
|
|
|
|
case WMSZ_BOTTOMLEFT:
|
|
|
|
case WMSZ_BOTTOMRIGHT:
|
|
|
|
r->bottom -= extra;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WMSZ_TOP:
|
|
|
|
case WMSZ_TOPLEFT:
|
|
|
|
case WMSZ_TOPRIGHT:
|
|
|
|
r->top += extra;
|
|
|
|
break;
|
|
|
|
}
|
2008-04-11 12:47:14 +00:00
|
|
|
int tooNarrow = (MIN_COLS*TEXT_WIDTH) - (r->right - r->left);
|
|
|
|
if(tooNarrow >= 0) {
|
|
|
|
switch(wParam) {
|
|
|
|
case WMSZ_RIGHT:
|
|
|
|
case WMSZ_BOTTOMRIGHT:
|
|
|
|
case WMSZ_TOPRIGHT:
|
|
|
|
r->right += tooNarrow;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WMSZ_LEFT:
|
|
|
|
case WMSZ_BOTTOMLEFT:
|
|
|
|
case WMSZ_TOPLEFT:
|
|
|
|
r->left -= tooNarrow;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-03-25 10:02:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_MOUSEMOVE: {
|
2008-05-27 06:36:59 +00:00
|
|
|
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) {
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
|
|
break;
|
|
|
|
}
|
2008-05-26 09:56:50 +00:00
|
|
|
GraphicsWindow::Selection ps = SS.GW.hover;
|
|
|
|
SS.GW.hover.Clear();
|
|
|
|
|
2008-03-28 10:00:37 +00:00
|
|
|
int x = LOWORD(lParam);
|
|
|
|
int y = HIWORD(lParam);
|
|
|
|
|
|
|
|
// Find the corresponding character in the text buffer
|
|
|
|
int c = (x / TEXT_WIDTH);
|
2008-04-28 07:18:39 +00:00
|
|
|
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) {
|
2008-03-28 10:00:37 +00:00
|
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
2008-05-26 09:56:50 +00:00
|
|
|
goto done;
|
2008-03-28 10:00:37 +00:00
|
|
|
}
|
|
|
|
|
2008-05-26 09:56:50 +00:00
|
|
|
#define META (SS.TW.meta[r][c])
|
2008-03-28 10:00:37 +00:00
|
|
|
if(msg == WM_MOUSEMOVE) {
|
2008-05-26 09:56:50 +00:00
|
|
|
if(META.link) {
|
2008-03-28 10:00:37 +00:00
|
|
|
SetCursor(LoadCursor(NULL, IDC_HAND));
|
2008-05-26 09:56:50 +00:00
|
|
|
if(META.h) {
|
|
|
|
(META.h)(META.link, META.data);
|
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
} else {
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
|
|
}
|
2008-04-11 12:47:14 +00:00
|
|
|
} else {
|
2008-05-26 09:56:50 +00:00
|
|
|
if(META.link && META.f) {
|
|
|
|
(META.f)(META.link, META.data);
|
2008-05-17 08:02:39 +00:00
|
|
|
SS.TW.Show();
|
|
|
|
InvalidateGraphics();
|
2008-04-11 12:47:14 +00:00
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
}
|
2008-05-26 09:56:50 +00:00
|
|
|
done:
|
|
|
|
if(!ps.Equals(&(SS.GW.hover))) {
|
|
|
|
InvalidateGraphics();
|
|
|
|
}
|
2008-03-28 10:00:37 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-04-01 10:48:44 +00:00
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
case WM_SIZE: {
|
|
|
|
RECT r;
|
|
|
|
GetWindowRect(TextWndScrollBar, &r);
|
|
|
|
int sw = r.right - r.left;
|
|
|
|
GetClientRect(hwnd, &r);
|
|
|
|
MoveWindow(TextWndScrollBar, r.right - sw, r.top, sw,
|
2008-04-12 14:12:26 +00:00
|
|
|
(r.bottom - r.top), TRUE);
|
2008-05-27 06:36:59 +00:00
|
|
|
// If the window is growing, then the scrollbar position may
|
|
|
|
// be moving, so it's as if we're dragging the scrollbar.
|
|
|
|
HandleTextWindowScrollBar(0, 0);
|
2008-03-25 10:02:13 +00:00
|
|
|
InvalidateRect(TextWnd, NULL, FALSE);
|
|
|
|
break;
|
|
|
|
}
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
case WM_VSCROLL:
|
|
|
|
HandleTextWindowScrollBar(wParam, lParam);
|
|
|
|
break;
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
default:
|
|
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
static BOOL ProcessKeyDown(WPARAM wParam)
|
|
|
|
{
|
2008-04-21 10:12:04 +00:00
|
|
|
if(GraphicsEditControlIsVisible() && wParam != VK_ESCAPE) {
|
|
|
|
if(wParam == VK_RETURN) {
|
|
|
|
char s[1024];
|
|
|
|
memset(s, 0, sizeof(s));
|
|
|
|
SendMessage(GraphicsEditControl, WM_GETTEXT, 900, (LPARAM)s);
|
|
|
|
SS.GW.EditControlDone(s);
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2008-05-27 06:36:59 +00:00
|
|
|
if(TextEditControlIsVisible() && wParam != VK_ESCAPE) {
|
|
|
|
if(wParam == VK_RETURN) {
|
|
|
|
char s[1024];
|
|
|
|
memset(s, 0, sizeof(s));
|
|
|
|
SendMessage(TextEditControl, WM_GETTEXT, 900, (LPARAM)s);
|
|
|
|
SS.TW.EditControlDone(s);
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2008-04-21 10:12:04 +00:00
|
|
|
|
2008-05-26 09:56:50 +00:00
|
|
|
if(wParam == VK_BACK && !GraphicsEditControlIsVisible()) {
|
2008-07-10 06:11:56 +00:00
|
|
|
TextWindow::ScreenHome(0, 0);
|
2008-05-26 09:56:50 +00:00
|
|
|
SS.TW.Show();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-04-12 15:17:58 +00:00
|
|
|
int c;
|
|
|
|
switch(wParam) {
|
|
|
|
case VK_OEM_PLUS: c = '+'; break;
|
|
|
|
case VK_OEM_MINUS: c = '-'; break;
|
|
|
|
case VK_ESCAPE: c = 27; break;
|
|
|
|
case VK_OEM_4: c = '['; break;
|
|
|
|
case VK_OEM_6: c = ']'; break;
|
|
|
|
case VK_OEM_5: c = '\\'; break;
|
|
|
|
case VK_SPACE: c = ' '; break;
|
|
|
|
case VK_DELETE: c = 127; break;
|
2008-04-27 05:00:12 +00:00
|
|
|
case VK_TAB: c = '\t'; break;
|
2008-04-12 15:17:58 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
c = wParam;
|
|
|
|
break;
|
|
|
|
}
|
2008-04-14 10:28:32 +00:00
|
|
|
if(GetAsyncKeyState(VK_SHIFT) & 0x8000) c |= 0x100;
|
|
|
|
if(GetAsyncKeyState(VK_CONTROL) & 0x8000) c |= 0x200;
|
2008-04-12 15:17:58 +00:00
|
|
|
|
|
|
|
for(int i = 0; SS.GW.menu[i].level >= 0; i++) {
|
|
|
|
if(c == SS.GW.menu[i].accel) {
|
|
|
|
(SS.GW.menu[i].fn)((GraphicsWindow::MenuId)SS.GW.menu[i].id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No accelerator; process the key as normal.
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-04-27 05:00:12 +00:00
|
|
|
void ShowTextWindow(BOOL visible)
|
|
|
|
{
|
|
|
|
ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE);
|
|
|
|
}
|
|
|
|
|
2008-05-16 04:54:47 +00:00
|
|
|
static void CreateGlContext(void)
|
|
|
|
{
|
|
|
|
HDC hdc = GetDC(GraphicsWnd);
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
|
|
int pixelFormat;
|
|
|
|
|
|
|
|
memset(&pfd, 0, sizeof(pfd));
|
|
|
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
|
|
|
pfd.nVersion = 1;
|
|
|
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
|
|
|
|
PFD_DOUBLEBUFFER;
|
|
|
|
pfd.dwLayerMask = PFD_MAIN_PLANE;
|
2008-04-11 11:13:47 +00:00
|
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
2008-07-09 06:41:42 +00:00
|
|
|
pfd.cColorBits = 32;
|
|
|
|
pfd.cDepthBits = 24;
|
2008-03-27 09:53:51 +00:00
|
|
|
pfd.cAccumBits = 0;
|
|
|
|
pfd.cStencilBits = 0;
|
|
|
|
|
|
|
|
pixelFormat = ChoosePixelFormat(hdc, &pfd);
|
|
|
|
if(!pixelFormat) oops();
|
|
|
|
|
|
|
|
if(!SetPixelFormat(hdc, pixelFormat, &pfd)) oops();
|
|
|
|
|
2008-05-16 04:54:47 +00:00
|
|
|
GraphicsHpgl = wglCreateContext(hdc);
|
|
|
|
wglMakeCurrent(hdc, GraphicsHpgl);
|
2008-03-27 09:53:51 +00:00
|
|
|
}
|
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
void InvalidateGraphics(void)
|
2008-03-27 09:53:51 +00:00
|
|
|
{
|
|
|
|
InvalidateRect(GraphicsWnd, NULL, FALSE);
|
|
|
|
}
|
2008-06-12 07:31:41 +00:00
|
|
|
void GetGraphicsWindowSize(int *w, int *h)
|
2008-04-18 11:11:48 +00:00
|
|
|
{
|
|
|
|
RECT r;
|
|
|
|
GetClientRect(GraphicsWnd, &r);
|
2008-06-12 07:31:41 +00:00
|
|
|
*w = r.right - r.left;
|
|
|
|
*h = r.bottom - r.top;
|
|
|
|
}
|
|
|
|
void PaintGraphics(void)
|
|
|
|
{
|
|
|
|
int w, h;
|
|
|
|
GetGraphicsWindowSize(&w, &h);
|
2008-04-18 11:11:48 +00:00
|
|
|
|
|
|
|
SS.GW.Paint(w, h);
|
2008-05-16 04:54:47 +00:00
|
|
|
SwapBuffers(GetDC(GraphicsWnd));
|
2008-04-18 11:11:48 +00:00
|
|
|
}
|
2008-05-16 04:54:47 +00:00
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
SDWORD GetMilliseconds(void)
|
|
|
|
{
|
2008-06-01 09:46:02 +00:00
|
|
|
LARGE_INTEGER t, f;
|
|
|
|
QueryPerformanceCounter(&t);
|
|
|
|
QueryPerformanceFrequency(&f);
|
|
|
|
LONGLONG d = t.QuadPart/(f.QuadPart/1000);
|
|
|
|
return (SDWORD)d;
|
2008-04-18 11:11:48 +00:00
|
|
|
}
|
|
|
|
|
2008-04-11 12:47:14 +00:00
|
|
|
void InvalidateText(void)
|
|
|
|
{
|
|
|
|
InvalidateRect(TextWnd, NULL, FALSE);
|
|
|
|
}
|
2008-03-27 09:53:51 +00:00
|
|
|
|
2008-05-27 06:36:59 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
void ShowTextEditControl(int hr, int c, char *s)
|
|
|
|
{
|
|
|
|
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return;
|
|
|
|
|
|
|
|
int x = TEXT_LEFT_MARGIN + TEXT_WIDTH*c;
|
|
|
|
int y = (hr - TextWndScrollPos)*(TEXT_HEIGHT/2);
|
|
|
|
TextEditControlCol = c;
|
|
|
|
TextEditControlHalfRow = hr;
|
|
|
|
ShowEditControl(TextEditControl, x, y, s);
|
|
|
|
}
|
|
|
|
void HideTextEditControl(void)
|
|
|
|
{
|
|
|
|
ShowWindow(TextEditControl, SW_HIDE);
|
|
|
|
}
|
|
|
|
BOOL TextEditControlIsVisible(void)
|
|
|
|
{
|
|
|
|
return IsWindowVisible(TextEditControl);
|
|
|
|
}
|
2008-04-21 10:12:04 +00:00
|
|
|
void ShowGraphicsEditControl(int x, int y, char *s)
|
|
|
|
{
|
2008-05-27 06:36:59 +00:00
|
|
|
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return;
|
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
RECT r;
|
|
|
|
GetClientRect(GraphicsWnd, &r);
|
|
|
|
x = x + (r.right - r.left)/2;
|
|
|
|
y = (r.bottom - r.top)/2 - y;
|
|
|
|
|
|
|
|
// (x, y) are the bottom left, but the edit control is placed by its
|
|
|
|
// top left corner
|
2008-04-22 13:14:15 +00:00
|
|
|
y -= 20;
|
2008-04-21 10:12:04 +00:00
|
|
|
|
2008-05-27 06:36:59 +00:00
|
|
|
ShowEditControl(GraphicsEditControl, x, y, s);
|
2008-04-21 10:12:04 +00:00
|
|
|
}
|
|
|
|
void HideGraphicsEditControl(void)
|
|
|
|
{
|
|
|
|
ShowWindow(GraphicsEditControl, SW_HIDE);
|
|
|
|
}
|
|
|
|
BOOL GraphicsEditControlIsVisible(void)
|
|
|
|
{
|
|
|
|
return IsWindowVisible(GraphicsEditControl);
|
|
|
|
}
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (msg) {
|
2008-03-27 09:53:51 +00:00
|
|
|
case WM_ERASEBKGND:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_SIZE:
|
|
|
|
InvalidateRect(GraphicsWnd, NULL, FALSE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_PAINT: {
|
2008-05-16 04:54:47 +00:00
|
|
|
PaintGraphics();
|
2008-03-27 09:53:51 +00:00
|
|
|
PAINTSTRUCT ps;
|
|
|
|
HDC hdc = BeginPaint(hwnd, &ps);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
case WM_LBUTTONDOWN:
|
2008-04-22 10:53:42 +00:00
|
|
|
case WM_LBUTTONUP:
|
2008-04-21 10:12:04 +00:00
|
|
|
case WM_LBUTTONDBLCLK:
|
2008-07-06 07:56:24 +00:00
|
|
|
case WM_RBUTTONDOWN:
|
2008-03-27 09:53:51 +00:00
|
|
|
case WM_MBUTTONDOWN: {
|
|
|
|
int x = LOWORD(lParam);
|
|
|
|
int y = HIWORD(lParam);
|
|
|
|
|
|
|
|
RECT r;
|
|
|
|
GetClientRect(GraphicsWnd, &r);
|
|
|
|
x = x - (r.right - r.left)/2;
|
|
|
|
y = (r.bottom - r.top)/2 - y;
|
|
|
|
|
2008-04-01 10:48:44 +00:00
|
|
|
LastMousePos.x = x;
|
|
|
|
LastMousePos.y = y;
|
|
|
|
|
2008-03-27 09:53:51 +00:00
|
|
|
if(msg == WM_LBUTTONDOWN) {
|
|
|
|
SS.GW.MouseLeftDown(x, y);
|
2008-04-22 10:53:42 +00:00
|
|
|
} else if(msg == WM_LBUTTONUP) {
|
|
|
|
SS.GW.MouseLeftUp(x, y);
|
2008-04-21 10:12:04 +00:00
|
|
|
} else if(msg == WM_LBUTTONDBLCLK) {
|
|
|
|
SS.GW.MouseLeftDoubleClick(x, y);
|
2008-07-06 07:56:24 +00:00
|
|
|
} else if(msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) {
|
|
|
|
SS.GW.MouseMiddleOrRightDown(x, y);
|
2008-03-27 09:53:51 +00:00
|
|
|
} else if(msg == WM_MOUSEMOVE) {
|
|
|
|
SS.GW.MouseMoved(x, y,
|
|
|
|
!!(wParam & MK_LBUTTON),
|
|
|
|
!!(wParam & MK_MBUTTON),
|
|
|
|
!!(wParam & MK_RBUTTON),
|
|
|
|
!!(wParam & MK_SHIFT),
|
|
|
|
!!(wParam & MK_CONTROL));
|
|
|
|
} else {
|
|
|
|
oops();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2008-04-01 10:48:44 +00:00
|
|
|
case WM_MOUSEWHEEL: {
|
|
|
|
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
|
|
|
|
SS.GW.MouseScroll(LastMousePos.x, LastMousePos.y, delta);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-12 15:17:58 +00:00
|
|
|
case WM_COMMAND: {
|
2008-04-21 10:12:04 +00:00
|
|
|
if(HIWORD(wParam) == 0) {
|
|
|
|
int id = LOWORD(wParam);
|
2008-05-28 10:10:31 +00:00
|
|
|
if((id >= RECENT_OPEN && id < (RECENT_OPEN + MAX_RECENT))) {
|
|
|
|
SolveSpace::MenuFile(id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if((id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT))) {
|
|
|
|
Group::MenuGroup(id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
int i;
|
|
|
|
for(i = 0; SS.GW.menu[i].level >= 0; i++) {
|
2008-04-21 10:12:04 +00:00
|
|
|
if(id == SS.GW.menu[i].id) {
|
|
|
|
(SS.GW.menu[i].fn)((GraphicsWindow::MenuId)id);
|
|
|
|
break;
|
|
|
|
}
|
2008-04-12 15:17:58 +00:00
|
|
|
}
|
2008-05-28 10:10:31 +00:00
|
|
|
if(SS.GW.menu[i].level < 0) oops();
|
2008-04-12 15:17:58 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2008-03-27 09:53:51 +00:00
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
case WM_CLOSE:
|
|
|
|
case WM_DESTROY:
|
2008-06-03 18:28:41 +00:00
|
|
|
SolveSpace::MenuFile(GraphicsWindow::MNU_EXIT);
|
2008-03-25 10:02:13 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Common dialog routines, to open or save a file.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
BOOL GetOpenFile(char *file, char *defExtension, char *selPattern)
|
|
|
|
{
|
|
|
|
OPENFILENAME ofn;
|
|
|
|
|
|
|
|
memset(&ofn, 0, sizeof(ofn));
|
|
|
|
ofn.lStructSize = sizeof(ofn);
|
|
|
|
ofn.hInstance = Instance;
|
|
|
|
ofn.hwndOwner = GraphicsWnd;
|
|
|
|
ofn.lpstrFilter = selPattern;
|
|
|
|
ofn.lpstrDefExt = defExtension;
|
|
|
|
ofn.lpstrFile = file;
|
|
|
|
ofn.nMaxFile = MAX_PATH;
|
|
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
|
|
|
|
|
|
|
|
EnableWindow(GraphicsWnd, FALSE);
|
2008-06-25 05:14:49 +00:00
|
|
|
EnableWindow(TextWnd, FALSE);
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
BOOL r = GetOpenFileName(&ofn);
|
2008-06-25 05:14:49 +00:00
|
|
|
|
|
|
|
EnableWindow(TextWnd, TRUE);
|
2008-04-18 11:11:48 +00:00
|
|
|
EnableWindow(GraphicsWnd, TRUE);
|
|
|
|
SetForegroundWindow(GraphicsWnd);
|
2008-06-25 05:14:49 +00:00
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
BOOL GetSaveFile(char *file, char *defExtension, char *selPattern)
|
|
|
|
{
|
|
|
|
OPENFILENAME ofn;
|
|
|
|
|
|
|
|
memset(&ofn, 0, sizeof(ofn));
|
|
|
|
ofn.lStructSize = sizeof(ofn);
|
|
|
|
ofn.hInstance = Instance;
|
|
|
|
ofn.hwndOwner = GraphicsWnd;
|
|
|
|
ofn.lpstrFilter = selPattern;
|
|
|
|
ofn.lpstrDefExt = defExtension;
|
|
|
|
ofn.lpstrFile = file;
|
|
|
|
ofn.nMaxFile = MAX_PATH;
|
|
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
|
|
|
|
|
|
|
|
EnableWindow(GraphicsWnd, FALSE);
|
2008-06-25 05:14:49 +00:00
|
|
|
EnableWindow(TextWnd, FALSE);
|
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
BOOL r = GetSaveFileName(&ofn);
|
2008-06-25 05:14:49 +00:00
|
|
|
|
|
|
|
EnableWindow(TextWnd, TRUE);
|
2008-04-18 11:11:48 +00:00
|
|
|
EnableWindow(GraphicsWnd, TRUE);
|
|
|
|
SetForegroundWindow(GraphicsWnd);
|
2008-06-25 05:14:49 +00:00
|
|
|
|
2008-04-18 11:11:48 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
int SaveFileYesNoCancel(void)
|
|
|
|
{
|
2008-06-25 05:14:49 +00:00
|
|
|
EnableWindow(GraphicsWnd, FALSE);
|
|
|
|
EnableWindow(TextWnd, FALSE);
|
|
|
|
|
|
|
|
int r = MessageBox(GraphicsWnd,
|
2008-04-18 11:11:48 +00:00
|
|
|
"The program has changed since it was last saved.\r\n\r\n"
|
|
|
|
"Do you want to save the changes?", "SolveSpace",
|
|
|
|
MB_YESNOCANCEL | MB_ICONWARNING);
|
|
|
|
|
2008-06-25 05:14:49 +00:00
|
|
|
EnableWindow(TextWnd, TRUE);
|
|
|
|
EnableWindow(GraphicsWnd, TRUE);
|
|
|
|
SetForegroundWindow(GraphicsWnd);
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2008-06-30 09:09:17 +00:00
|
|
|
|
2008-06-25 05:14:49 +00:00
|
|
|
void GetAbsoluteFilename(char *file)
|
|
|
|
{
|
|
|
|
char absoluteFile[MAX_PATH];
|
|
|
|
GetFullPathName(file, sizeof(absoluteFile), absoluteFile, NULL);
|
|
|
|
strcpy(file, absoluteFile);
|
|
|
|
}
|
2008-04-18 11:11:48 +00:00
|
|
|
|
2008-06-30 09:09:17 +00:00
|
|
|
void LoadAllFontFiles(void)
|
|
|
|
{
|
|
|
|
WIN32_FIND_DATA wfd;
|
|
|
|
char dir[MAX_PATH];
|
|
|
|
GetWindowsDirectory(dir, MAX_PATH - 30);
|
|
|
|
strcat(dir, "\\fonts\\*.ttf");
|
|
|
|
|
|
|
|
HANDLE h = FindFirstFile(dir, &wfd);
|
|
|
|
|
|
|
|
while(h != INVALID_HANDLE_VALUE) {
|
|
|
|
TtfFont tf;
|
|
|
|
ZERO(&tf);
|
|
|
|
|
|
|
|
char fullPath[MAX_PATH];
|
|
|
|
GetWindowsDirectory(fullPath, MAX_PATH - (30 + strlen(wfd.cFileName)));
|
|
|
|
strcat(fullPath, "\\fonts\\");
|
|
|
|
strcat(fullPath, wfd.cFileName);
|
|
|
|
|
|
|
|
strcpy(tf.fontFile, fullPath);
|
|
|
|
SS.fonts.l.Add(&tf);
|
|
|
|
|
|
|
|
if(!FindNextFile(h, &wfd)) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-18 07:06:37 +00:00
|
|
|
static void MenuById(int id, BOOL yes, BOOL check)
|
2008-04-14 10:28:32 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int subMenu = -1;
|
|
|
|
|
|
|
|
for(i = 0; SS.GW.menu[i].level >= 0; i++) {
|
|
|
|
if(SS.GW.menu[i].level == 0) subMenu++;
|
|
|
|
|
|
|
|
if(SS.GW.menu[i].id == id) {
|
|
|
|
if(subMenu < 0) oops();
|
|
|
|
if(subMenu >= (sizeof(SubMenus)/sizeof(SubMenus[0]))) oops();
|
|
|
|
|
2008-04-18 07:06:37 +00:00
|
|
|
if(check) {
|
|
|
|
CheckMenuItem(SubMenus[subMenu], id,
|
|
|
|
yes ? MF_CHECKED : MF_UNCHECKED);
|
|
|
|
} else {
|
|
|
|
EnableMenuItem(SubMenus[subMenu], id,
|
|
|
|
yes ? MF_ENABLED : MF_GRAYED);
|
|
|
|
}
|
2008-04-14 10:28:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
oops();
|
|
|
|
}
|
2008-04-18 07:06:37 +00:00
|
|
|
void CheckMenuById(int id, BOOL checked)
|
|
|
|
{
|
|
|
|
MenuById(id, checked, TRUE);
|
|
|
|
}
|
|
|
|
void EnableMenuById(int id, BOOL enabled)
|
|
|
|
{
|
|
|
|
MenuById(id, enabled, FALSE);
|
|
|
|
}
|
2008-05-28 10:10:31 +00:00
|
|
|
static void DoRecent(HMENU m, int base)
|
|
|
|
{
|
|
|
|
while(DeleteMenu(m, 0, MF_BYPOSITION))
|
|
|
|
;
|
|
|
|
int i, c = 0;
|
|
|
|
for(i = 0; i < MAX_RECENT; i++) {
|
|
|
|
char *s = RecentFile[i];
|
|
|
|
if(*s) {
|
|
|
|
AppendMenu(m, MF_STRING, base+i, s);
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(c == 0) AppendMenu(m, MF_STRING | MF_GRAYED, 0, "(no recent files)");
|
|
|
|
}
|
|
|
|
void RefreshRecentMenus(void)
|
|
|
|
{
|
|
|
|
DoRecent(RecentOpenMenu, RECENT_OPEN);
|
|
|
|
DoRecent(RecentImportMenu, RECENT_IMPORT);
|
|
|
|
}
|
2008-04-14 10:28:32 +00:00
|
|
|
|
2008-03-26 09:18:12 +00:00
|
|
|
HMENU CreateGraphicsWindowMenus(void)
|
|
|
|
{
|
|
|
|
HMENU top = CreateMenu();
|
|
|
|
HMENU m;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
int subMenu = 0;
|
|
|
|
|
|
|
|
for(i = 0; SS.GW.menu[i].level >= 0; i++) {
|
|
|
|
if(SS.GW.menu[i].level == 0) {
|
|
|
|
m = CreateMenu();
|
|
|
|
AppendMenu(top, MF_STRING | MF_POPUP, (UINT_PTR)m,
|
|
|
|
SS.GW.menu[i].label);
|
|
|
|
|
|
|
|
if(subMenu >= arraylen(SubMenus)) oops();
|
|
|
|
SubMenus[subMenu] = m;
|
|
|
|
subMenu++;
|
2008-05-28 10:10:31 +00:00
|
|
|
} else if(SS.GW.menu[i].level == 1) {
|
2008-03-26 09:18:12 +00:00
|
|
|
if(SS.GW.menu[i].label) {
|
|
|
|
AppendMenu(m, MF_STRING, SS.GW.menu[i].id, SS.GW.menu[i].label);
|
|
|
|
} else {
|
|
|
|
AppendMenu(m, MF_SEPARATOR, SS.GW.menu[i].id, "");
|
|
|
|
}
|
2008-05-28 10:10:31 +00:00
|
|
|
} else if(SS.GW.menu[i].level == 10) {
|
|
|
|
RecentOpenMenu = CreateMenu();
|
|
|
|
AppendMenu(m, MF_STRING | MF_POPUP,
|
|
|
|
(UINT_PTR)RecentOpenMenu, SS.GW.menu[i].label);
|
|
|
|
} else if(SS.GW.menu[i].level == 11) {
|
|
|
|
RecentImportMenu = CreateMenu();
|
|
|
|
AppendMenu(m, MF_STRING | MF_POPUP,
|
|
|
|
(UINT_PTR)RecentImportMenu, SS.GW.menu[i].label);
|
|
|
|
} else oops();
|
2008-03-26 09:18:12 +00:00
|
|
|
}
|
2008-05-28 10:10:31 +00:00
|
|
|
RefreshRecentMenus();
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
return top;
|
|
|
|
}
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
static void CreateMainWindows(void)
|
|
|
|
{
|
|
|
|
WNDCLASSEX wc;
|
|
|
|
|
|
|
|
memset(&wc, 0, sizeof(wc));
|
|
|
|
wc.cbSize = sizeof(wc);
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
// The graphics window, where the sketch is drawn and shown.
|
2008-03-25 10:02:13 +00:00
|
|
|
wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC |
|
|
|
|
CS_DBLCLKS;
|
2008-03-26 09:18:12 +00:00
|
|
|
wc.lpfnWndProc = (WNDPROC)GraphicsWndProc;
|
2008-03-27 09:53:51 +00:00
|
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
2008-03-26 09:18:12 +00:00
|
|
|
wc.lpszClassName = "GraphicsWnd";
|
2008-03-25 10:02:13 +00:00
|
|
|
wc.lpszMenuName = NULL;
|
|
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
wc.hIcon = NULL;
|
|
|
|
wc.hIconSm = NULL;
|
|
|
|
if(!RegisterClassEx(&wc)) oops();
|
|
|
|
|
2008-03-26 09:18:12 +00:00
|
|
|
HMENU top = CreateGraphicsWindowMenus();
|
2008-04-12 14:12:26 +00:00
|
|
|
GraphicsWnd = CreateWindowEx(0, "GraphicsWnd",
|
|
|
|
"SolveSpace (Graphics Window)",
|
2008-03-25 10:02:13 +00:00
|
|
|
WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX |
|
2008-03-27 09:53:51 +00:00
|
|
|
WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_CLIPSIBLINGS,
|
2008-05-27 09:59:19 +00:00
|
|
|
50, 50, 900, 600, NULL, top, Instance, NULL);
|
2008-03-26 09:18:12 +00:00
|
|
|
if(!GraphicsWnd) oops();
|
|
|
|
|
2008-05-16 04:54:47 +00:00
|
|
|
CreateGlContext();
|
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
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);
|
|
|
|
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
// The text window, with a comand line and some textual information
|
|
|
|
// about the sketch.
|
2008-04-11 12:47:14 +00:00
|
|
|
wc.style &= ~CS_DBLCLKS;
|
2008-03-26 09:18:12 +00:00
|
|
|
wc.lpfnWndProc = (WNDPROC)TextWndProc;
|
|
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
|
|
wc.lpszClassName = "TextWnd";
|
2008-03-28 10:00:37 +00:00
|
|
|
wc.hCursor = NULL;
|
2008-03-26 09:18:12 +00:00
|
|
|
if(!RegisterClassEx(&wc)) oops();
|
|
|
|
|
|
|
|
// We get the desired Alt+Tab behaviour by specifying that the text
|
|
|
|
// window is a child of the graphics window.
|
|
|
|
TextWnd = CreateWindowEx(0,
|
2008-04-27 09:31:56 +00:00
|
|
|
"TextWnd", "SolveSpace (Text Window)", WS_THICKFRAME | WS_CLIPCHILDREN,
|
2008-05-27 09:59:19 +00:00
|
|
|
650, 500, 420, 300, GraphicsWnd, (HMENU)NULL, Instance, NULL);
|
2008-03-25 10:02:13 +00:00
|
|
|
if(!TextWnd) oops();
|
|
|
|
|
|
|
|
TextWndScrollBar = CreateWindowEx(0, WC_SCROLLBAR, "", WS_CHILD |
|
|
|
|
SBS_VERT | SBS_LEFTALIGN | WS_VISIBLE | WS_CLIPSIBLINGS,
|
|
|
|
200, 100, 100, 100, TextWnd, NULL, Instance, NULL);
|
|
|
|
// Force the scrollbar to get resized to the window,
|
|
|
|
TextWndProc(TextWnd, WM_SIZE, 0, 0);
|
|
|
|
|
2008-05-27 06:36:59 +00:00
|
|
|
TextEditControl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, "",
|
|
|
|
WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS,
|
|
|
|
50, 50, 100, 21, TextWnd, NULL, Instance, NULL);
|
|
|
|
SendMessage(TextEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE);
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
|
|
|
|
RECT r, rc;
|
|
|
|
GetWindowRect(TextWnd, &r);
|
|
|
|
GetClientRect(TextWnd, &rc);
|
|
|
|
ClientIsSmallerBy = (r.bottom - r.top) - (rc.bottom - rc.top);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Entry point into the program.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
|
|
LPSTR lpCmdLine, INT nCmdShow)
|
|
|
|
{
|
|
|
|
Instance = hInstance;
|
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
InitCommonControls();
|
2008-03-26 09:18:12 +00:00
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
// A monospaced font
|
2008-04-28 07:18:39 +00:00
|
|
|
FixedFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
|
2008-03-25 10:02:13 +00:00
|
|
|
FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
|
|
|
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
|
2008-04-28 07:18:39 +00:00
|
|
|
LinkFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
|
2008-03-28 10:00:37 +00:00
|
|
|
TRUE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
|
|
|
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
|
2008-03-25 10:02:13 +00:00
|
|
|
if(!FixedFont)
|
|
|
|
FixedFont = (HFONT)GetStockObject(SYSTEM_FONT);
|
2008-03-28 10:00:37 +00:00
|
|
|
if(!LinkFont)
|
|
|
|
LinkFont = (HFONT)GetStockObject(SYSTEM_FONT);
|
2008-03-25 10:02:13 +00:00
|
|
|
|
2008-04-21 10:12:04 +00:00
|
|
|
// Create the root windows: one for control, with text, and one for
|
|
|
|
// the graphics
|
|
|
|
CreateMainWindows();
|
|
|
|
|
|
|
|
ThawWindowPos(TextWnd);
|
|
|
|
ThawWindowPos(GraphicsWnd);
|
|
|
|
|
2008-05-07 04:17:29 +00:00
|
|
|
// Create the heap used for long-lived stuff (that gets freed piecewise).
|
|
|
|
Perm = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
2008-04-25 10:11:29 +00:00
|
|
|
// Create the heap that we use to store Exprs and other temp stuff.
|
|
|
|
FreeAllTemporary();
|
2008-04-13 14:28:35 +00:00
|
|
|
|
2008-06-16 08:35:05 +00:00
|
|
|
// A filename may have been specified on the command line; if so, then
|
|
|
|
// strip any quotation marks, and make it absolute.
|
|
|
|
char file[MAX_PATH] = "";
|
|
|
|
if(strlen(lpCmdLine)+1 < MAX_PATH) {
|
|
|
|
char *s = lpCmdLine;
|
|
|
|
while(*s == ' ' || *s == '"') s++;
|
|
|
|
strcpy(file, s);
|
|
|
|
s = strrchr(file, '"');
|
|
|
|
if(s) *s = '\0';
|
|
|
|
}
|
|
|
|
if(*file != '\0') {
|
2008-06-25 05:14:49 +00:00
|
|
|
GetAbsoluteFilename(file);
|
2008-06-16 08:35:05 +00:00
|
|
|
}
|
|
|
|
|
2008-03-25 10:02:13 +00:00
|
|
|
// Call in to the platform-independent code, and let them do their init
|
2008-06-25 05:14:49 +00:00
|
|
|
SS.Init(file);
|
2008-03-26 09:18:12 +00:00
|
|
|
|
|
|
|
ShowWindow(TextWnd, SW_SHOWNOACTIVATE);
|
|
|
|
ShowWindow(GraphicsWnd, SW_SHOW);
|
2008-03-25 10:02:13 +00:00
|
|
|
|
|
|
|
// And now it's the message loop. All calls in to the rest of the code
|
|
|
|
// will be from the wndprocs.
|
|
|
|
MSG msg;
|
|
|
|
DWORD ret;
|
|
|
|
while(ret = GetMessage(&msg, NULL, 0, 0)) {
|
2008-04-12 15:17:58 +00:00
|
|
|
if(msg.message == WM_KEYDOWN) {
|
2008-06-03 18:28:41 +00:00
|
|
|
if(ProcessKeyDown(msg.wParam)) goto done;
|
|
|
|
}
|
|
|
|
if(msg.message == WM_SYSKEYDOWN && msg.hwnd == TextWnd) {
|
|
|
|
// If the user presses the Alt key when the text window has focus,
|
|
|
|
// then that should probably go to the graphics window instead.
|
|
|
|
SetForegroundWindow(GraphicsWnd);
|
2008-04-12 15:17:58 +00:00
|
|
|
}
|
2008-03-25 10:02:13 +00:00
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessage(&msg);
|
2008-06-03 18:28:41 +00:00
|
|
|
done:
|
|
|
|
SS.DoLater();
|
2008-03-25 10:02:13 +00:00
|
|
|
}
|
2008-05-28 10:10:31 +00:00
|
|
|
|
|
|
|
// Write everything back to the registry
|
2008-03-26 09:18:12 +00:00
|
|
|
FreezeWindowPos(TextWnd);
|
|
|
|
FreezeWindowPos(GraphicsWnd);
|
2008-03-25 10:02:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|