From fcdf43d487e922d27e9ab6153a8b246601e2479e Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Wed, 26 Mar 2008 01:18:12 -0800 Subject: [PATCH] More fragments of SolveSpace work. Improve the command line window, and add some (non-functional) menus to the graphics window. Start to rough in some data structures to hold the sketch. No real work yet, though. [git-p4: depot-paths = "//depot/solvespace/": change = 1653] --- Makefile | 3 +- cmdline.cpp | 41 +++++++++-- dsc.h | 16 +++++ graphicswin.cpp | 35 +++++++++ sketch.h | 58 +++++++++++++++ solvespace.cpp | 6 +- solvespace.h | 16 ++++- ui.h | 22 ++++++ win32/w32main.cpp | 177 +++++++++++++++++++++++++++++++++++++--------- 9 files changed, 331 insertions(+), 43 deletions(-) create mode 100644 graphicswin.cpp create mode 100644 sketch.h diff --git a/Makefile b/Makefile index 5d125d1..ec52930 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ DEFINES = /D_WIN32_WINNT=0x400 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x500 /DWIN32_LEAN_AND_MEAN /DWIN32 CFLAGS = /W3 /nologo -I..\common\win32 /O2 /D_DEBUG /D_CRT_SECURE_NO_WARNINGS /Zi /I. -HEADERS = ..\common\win32\freeze.h ui.h solvespace.h dsc.h +HEADERS = ..\common\win32\freeze.h ui.h solvespace.h dsc.h sketch.h OBJDIR = obj @@ -11,6 +11,7 @@ W32OBJS = $(OBJDIR)\w32main.obj \ SSOBJS = $(OBJDIR)\solvespace.obj \ $(OBJDIR)\cmdline.obj \ + $(OBJDIR)\graphicswin.obj \ LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib diff --git a/cmdline.cpp b/cmdline.cpp index 0bae73a..171147c 100644 --- a/cmdline.cpp +++ b/cmdline.cpp @@ -2,6 +2,11 @@ #include void TextWindow::Init(void) { + ClearScreen(); + ClearCommand(); +} + +void TextWindow::ClearScreen(void) { int i, j; for(i = 0; i < MAX_ROWS; i++) { for(j = 0; j < MAX_COLS; j++) { @@ -10,7 +15,8 @@ void TextWindow::Init(void) { meta[i][j].link = NOT_A_LINK; } } - ClearCommand(); + row0 = 0; + rows = 0; } void TextWindow::Printf(char *fmt, ...) { @@ -35,6 +41,26 @@ void TextWindow::Printf(char *fmt, ...) { c = 0; while(*fmt) { if(*fmt == '%') { + fmt++; + if(*fmt == '\0') goto done; + switch(*fmt) { + case 's': { + char *s = va_arg(vl, char *); + memcpy(&(text[r][c]), s, strlen(s)); + c += strlen(s); + break; + } + case 'd': { + int v = va_arg(vl, int); + sprintf((char *)&(text[r][c]), "%d", v); + c += strlen((char *)&(text[r][c])); + text[r][c] = ' '; + break; + } + case '%': + text[r][c++] = '%'; + break; + } } else { if(c >= MAX_COLS) goto done; text[r][c++] = *fmt; @@ -54,8 +80,11 @@ void TextWindow::ClearCommand(void) { memcpy(cmd, "+> ", 3); cmdLen = 0; cmdInsert = 3; - row0 = 0; - rows = 0; +} + +void TextWindow::ProcessCommand(char *cmd) +{ + Printf("command: '%s'", cmd); } void TextWindow::KeyPressed(int c) { @@ -65,11 +94,15 @@ void TextWindow::KeyPressed(int c) { } if(c == '\n' || c == '\r') { - // process the command, and then + cmd[cmdLen+3] = '\0'; + ProcessCommand(cmd+3); + ClearCommand(); return; } else if(c == 27) { ClearCommand(); + } else if(c == 'l' - 'a' + 1) { + ClearScreen(); } else if(c == '\b') { // backspace, delete from insertion point if(cmdInsert <= 3) return; diff --git a/dsc.h b/dsc.h index 5b59c93..945054b 100644 --- a/dsc.h +++ b/dsc.h @@ -9,4 +9,20 @@ typedef struct { double x, y, z; } Vector; +template struct IdList { + typedef struct { + T v; + int tag; + } Elem; + + Elem elem; + int elems; + int elemsAllocated; + + void addAndAssignId(T *v); + void removeTagged(void); + + void clear(void); +}; + #endif diff --git a/graphicswin.cpp b/graphicswin.cpp new file mode 100644 index 0000000..0be61a4 --- /dev/null +++ b/graphicswin.cpp @@ -0,0 +1,35 @@ +#include "solvespace.h" +#include + +const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { + { 0, "&File", 0, NULL }, + { 1, "&New\tCtrl+N", 0, NULL }, + { 1, "&Open...\tCtrl+O", 0, NULL }, + { 1, "&Save\tCtrl+S", 0, NULL }, + { 1, "Save &As...", 0, NULL }, + { 1, NULL, 0, NULL }, + { 1, "E&xit", 0, NULL }, + + { 0, "&Edit", 0, NULL }, + { 1, "&Undo\tCtrl+Z", 0, NULL }, + { 1, "&Redo\tCtrl+Y", 0, NULL }, + { 0, "&View", 0, NULL }, + { 1, "Zoom &In\t+", 0, NULL }, + { 1, "Zoom &Out\t-", 0, NULL }, + { 1, "Zoom To &Fit\tF", 0, NULL }, + { 1, NULL, 0, NULL }, + { 1, "Dimensions in &Inches", 0, NULL }, + { 1, "Dimensions in &Millimeters", 0, NULL }, + + { 0, "&Sketch", 0, NULL }, + { 1, NULL, 0, NULL }, + { 1, "To&ggle Construction\tG", 0, NULL }, + + { 0, "&Constrain", 0, NULL }, + { 1, "S&ymmetric\tY", 0, NULL }, + + { 0, "&Help", 0, NULL }, + { 1, "&About\t", 0, NULL }, + { -1 }, +}; + diff --git a/sketch.h b/sketch.h new file mode 100644 index 0000000..e586dfb --- /dev/null +++ b/sketch.h @@ -0,0 +1,58 @@ + +#ifndef __SKETCH_H +#define __SKETCH_H + +typedef struct hRequestTag hRequest; +typedef struct hEntityTag hEntity; +typedef struct hPointTag hPoint; +typedef struct hParamTag hParam; + +typedef struct hRequestTag { + int v; + + hEntity entity(int i); +} hRequest; + +typedef struct { + static const int REQUEST_LINE_SEGMENT = 0; + static const int REQUEST_STEP_REPEAT_TRANSLATE = 1; + static const int REQUEST_STEP_REPEAT_TRANSLATE_SYM = 2; + int type; + + hRequest h; +} Request; + +typedef struct hEntityTag { + int v; + + hRequest request(int i); + hPoint point(int i); +} hEntity; + +typedef struct { + static const int ENTITY_LINE_SEGMENT = 0; + static const int ENTITY_PWL_SEGMENT = 1; + int type; + + hEntity h; +} Entity; + +typedef struct hPointTag { +} hPoint; + +typedef struct { + + hPoint h; +} Point; + +typedef struct hParamTag { +} hParam; + +typedef struct { + double val; + + hParam h; +} Param; + +#endif + diff --git a/solvespace.cpp b/solvespace.cpp index a56cc81..cca84e3 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -5,7 +5,9 @@ SolveSpace SS; void SolveSpace::Init(void) { TW.Init(); - TW.Printf("She walks in beauty"); - TW.Printf("like the night"); + int i; + for(i = 0; i < 20; i++) { + TW.Printf("this is line number %d", i); + } } diff --git a/solvespace.h b/solvespace.h index 058fe07..aa86fae 100644 --- a/solvespace.h +++ b/solvespace.h @@ -4,16 +4,26 @@ #include #include +#include #include "dsc.h" #include "ui.h" +#include "sketch.h" // Debugging functions -#define oops() exit(-1) +#define oops() do { dbp("oops at line %d, file %s", __LINE__, __FILE__); \ + exit(-1); } while(0) void dbp(char *str, ...); +#define arraylen(x) (sizeof((x))/sizeof((x)[0])) + typedef struct { - TextWindow TW; - GraphicsWindow GW; + TextWindow TW; + GraphicsWindow GW; + + IdList req; + IdList entity; + IdList point; + IdList param; void Init(void); } SolveSpace; diff --git a/ui.h b/ui.h index 603a2a3..4986533 100644 --- a/ui.h +++ b/ui.h @@ -6,6 +6,14 @@ typedef struct { static const int MAX_COLS = 200; static const int MAX_ROWS = 500; +#ifndef RGB +#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16)) +#endif + static const int COLOR_BG_DEFAULT = RGB( 15, 15, 0); + static const int COLOR_FG_DEFAULT = RGB(255, 255, 255); + static const int COLOR_BG_CMDLINE = RGB( 0, 20, 80); + static const int COLOR_FG_CMDLINE = RGB(255, 255, 255); + // The line with the user-typed command, that is currently being edited. char cmd[MAX_COLS]; int cmdInsert; @@ -33,12 +41,25 @@ typedef struct { void ClearCommand(void); + void ProcessCommand(char *cmd); + // These are called by the platform-specific code. void KeyPressed(int c); bool IsHyperlink(int width, int height); } TextWindow; typedef struct { + // This table describes the top-level menus in the graphics winodw. + typedef void MenuHandler(int id); + typedef struct { + int level; // 0 == on menu bar, 1 == one level down, ... + char *label; // or NULL for a separator + int id; // unique ID + MenuHandler *fn; + } MenuEntry; + static const MenuEntry menu[]; + + // These parameters define the map from 2d screen coordinates to the // coordinates of the 3d sketch points. We will use an axonometric // projection. @@ -56,4 +77,5 @@ typedef struct { void MouseScroll(int delta); } GraphicsWindow; + #endif diff --git a/win32/w32main.cpp b/win32/w32main.cpp index d04dca7..04bcdc9 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -1,10 +1,14 @@ -#include "solvespace.h" #include #include #include #include #include +#include "solvespace.h" + +#define FREEZE_SUBKEY "SolveSpace" +#include "freeze.h" + #define TEXT_HEIGHT 18 #define TEXT_WIDTH 10 @@ -13,6 +17,9 @@ HINSTANCE Instance; HWND TextWnd, GraphicsWnd; HWND TextWndScrollBar; int TextWndScrollPos; +int TextWndRows; + +HMENU SubMenus[100]; int ClientIsSmallerBy; @@ -32,15 +39,24 @@ static void PaintTextWnd(HDC hdc) { RECT rect; GetClientRect(TextWnd, &rect); - FillRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); - SelectObject(hdc, FixedFont); - SetTextColor(hdc, RGB(255, 255, 255)); - SetBkColor(hdc, RGB(0, 0, 0)); + // 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); - int h = rect.bottom - rect.top; - int rows = h / TEXT_HEIGHT; + HBRUSH hbr = CreateSolidBrush(SS.TW.COLOR_BG_DEFAULT); + FillRect(backDc, &rect, hbr); + + SelectObject(backDc, FixedFont); + SetTextColor(backDc, SS.TW.COLOR_FG_DEFAULT); + SetBkColor(backDc, SS.TW.COLOR_BG_DEFAULT); + + int rows = height / TEXT_HEIGHT; rows--; + TextWndRows = rows; // Let's set up the scroll bar first SCROLLINFO si; @@ -62,12 +78,57 @@ static void PaintTextWnd(HDC hdc) for(c = 0; c < SS.TW.MAX_COLS; c++) { char v = '0' + (c % 10); - TextOut(hdc, 4 + c*TEXT_WIDTH, r*TEXT_HEIGHT, + TextOut(backDc, 4 + c*TEXT_WIDTH, (r-TextWndScrollPos)*TEXT_HEIGHT, (char *)&(SS.TW.text[rr][c]), 1); } } - TextOut(hdc, 4, rows*TEXT_HEIGHT, SS.TW.cmd, SS.TW.MAX_COLS); + SetTextColor(backDc, SS.TW.COLOR_FG_CMDLINE); + SetBkColor(backDc, SS.TW.COLOR_BG_CMDLINE); + TextOut(backDc, 4, rows*TEXT_HEIGHT, SS.TW.cmd, SS.TW.MAX_COLS); + + HPEN cpen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0)); + SelectObject(backDc, cpen); + int y = (rows+1)*TEXT_HEIGHT - 3; + MoveToEx(backDc, 4+(SS.TW.cmdInsert*TEXT_WIDTH), y, NULL); + LineTo(backDc, 4+(SS.TW.cmdInsert*TEXT_WIDTH)+TEXT_WIDTH, y); + + // And commit the back buffer + BitBlt(hdc, 0, 0, width, height, backDc, 0, 0, SRCCOPY); + DeleteObject(backBitmap); + DeleteObject(hbr); + DeleteObject(cpen); + DeleteDC(backDc); +} + +void HandleTextWindowScrollBar(WPARAM wParam, LPARAM lParam) +{ + int prevPos = TextWndScrollPos; + switch(LOWORD(wParam)) { + case SB_LINEUP: + case SB_PAGEUP: TextWndScrollPos--; break; + + case SB_LINEDOWN: + case SB_PAGEDOWN: TextWndScrollPos++; break; + + case SB_TOP: TextWndScrollPos = 0; break; + + case SB_BOTTOM: TextWndScrollPos = SS.TW.rows; break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: TextWndScrollPos = HIWORD(wParam); break; + } + TextWndScrollPos = max(0, TextWndScrollPos); + TextWndScrollPos = min(SS.TW.rows - TextWndRows, TextWndScrollPos); + if(prevPos != TextWndScrollPos) { + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = TextWndScrollPos; + SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE); + + InvalidateRect(TextWnd, NULL, FALSE); + } } LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -105,12 +166,12 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } hc = (r->bottom - r->top) - ClientIsSmallerBy; extra = hc % TEXT_HEIGHT; - dbp("extra=%d", extra); break; } case WM_CHAR: SS.TW.KeyPressed(wParam); + HandleTextWindowScrollBar(SB_BOTTOM, 0); InvalidateRect(TextWnd, NULL, FALSE); break; @@ -124,6 +185,11 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) InvalidateRect(TextWnd, NULL, FALSE); break; } + + case WM_VSCROLL: + HandleTextWindowScrollBar(wParam, lParam); + break; + default: return DefWindowProc(hwnd, msg, wParam, lParam); } @@ -135,6 +201,13 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { + case WM_CHAR: + SS.TW.KeyPressed(wParam); + SetForegroundWindow(TextWnd); + HandleTextWindowScrollBar(SB_BOTTOM, 0); + InvalidateRect(TextWnd, NULL, FALSE); + break; + case WM_CLOSE: case WM_DESTROY: PostQuitMessage(0); @@ -147,30 +220,76 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, return 1; } +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++; + } else { + 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, ""); + } + } + } + + return top; +} + static void CreateMainWindows(void) { WNDCLASSEX wc; - // The text window, with a comand line and some textual information - // about the sketch. memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); + + // The graphics window, where the sketch is drawn and shown. wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC | CS_DBLCLKS; - wc.lpfnWndProc = (WNDPROC)TextWndProc; - wc.hInstance = Instance; + wc.lpfnWndProc = (WNDPROC)GraphicsWndProc; wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = "TextWnd"; + wc.lpszClassName = "GraphicsWnd"; wc.lpszMenuName = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = NULL; wc.hIconSm = NULL; if(!RegisterClassEx(&wc)) oops(); - TextWnd = CreateWindowEx(0, "TextWnd", "SolveSpace (Command Line)", + HMENU top = CreateGraphicsWindowMenus(); + GraphicsWnd = CreateWindowEx(0, "GraphicsWnd", "SolveSpace (View Sketch)", WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX, - 10, 10, 600, 300, NULL, (HMENU)NULL, Instance, NULL); + 600, 300, 400, 400, NULL, top, Instance, NULL); + if(!GraphicsWnd) oops(); + + + // The text window, with a comand line and some textual information + // about the sketch. + wc.lpfnWndProc = (WNDPROC)TextWndProc; + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszClassName = "TextWnd"; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + 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, + "TextWnd", "SolveSpace (Command Line)", + WS_THICKFRAME | WS_CLIPCHILDREN, + 10, 10, 600, 300, GraphicsWnd, (HMENU)NULL, Instance, NULL); if(!TextWnd) oops(); TextWndScrollBar = CreateWindowEx(0, WC_SCROLLBAR, "", WS_CHILD | @@ -179,22 +298,6 @@ static void CreateMainWindows(void) // Force the scrollbar to get resized to the window, TextWndProc(TextWnd, WM_SIZE, 0, 0); - ShowWindow(TextWnd, SW_SHOW); - - // The graphics window, where the sketch is drawn and shown. - wc.lpfnWndProc = (WNDPROC)GraphicsWndProc; - wc.hInstance = Instance; - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = "GraphicsWnd"; - if(!RegisterClassEx(&wc)) oops(); - - GraphicsWnd = CreateWindowEx(0, "GraphicsWnd", "SolveSpace (View Sketch)", - WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX | - WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX, - 600, 300, 400, 400, NULL, (HMENU)NULL, Instance, NULL); - if(!GraphicsWnd) oops(); - - ShowWindow(GraphicsWnd, SW_SHOW); RECT r, rc; GetWindowRect(TextWnd, &r); @@ -214,6 +317,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, // the graphics CreateMainWindows(); + ThawWindowPos(TextWnd); + ThawWindowPos(GraphicsWnd); + // A monospaced font FixedFont = CreateFont(TEXT_HEIGHT-1, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, @@ -223,6 +329,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, // Call in to the platform-independent code, and let them do their init SS.Init(); + + ShowWindow(TextWnd, SW_SHOWNOACTIVATE); + ShowWindow(GraphicsWnd, SW_SHOW); // And now it's the message loop. All calls in to the rest of the code // will be from the wndprocs. @@ -232,6 +341,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, TranslateMessage(&msg); DispatchMessage(&msg); } + FreezeWindowPos(TextWnd); + FreezeWindowPos(GraphicsWnd); return 0; }