diff --git a/graphicswin.cpp b/graphicswin.cpp index 1b58a95..e7d6a1e 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -31,9 +31,6 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView }, { 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView }, { 1, NULL, 0, NULL }, -{ 1, "&Onto Plane / Coordinate System\tO", MNU_ORIENT_ONTO, 'O', mView }, -{ 1, "&Lock Orientation\tL", MNU_LOCK_VIEW, 'L', mView }, -{ 1, NULL, 0, NULL }, { 1, "Dimensions in &Inches", MNU_UNITS_INCHES, 0, mView }, { 1, "Dimensions in &Millimeters", MNU_UNITS_MM, 0, mView }, @@ -100,6 +97,10 @@ void GraphicsWindow::Init(void) { EnsureValidActives(); + // Start locked on to the XY plane. + hRequest r = Request::HREQUEST_REFERENCE_XY; + activeCsys = r.entity(0); + show2dCsyss = true; showAxes = true; showPoints = true; @@ -124,6 +125,42 @@ Point2d GraphicsWindow::ProjectPoint(Vector p) { return r; } +void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) { + // Get our initial orientation and translation. + Quaternion quat0 = Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp); + Vector offset0 = SS.GW.offset; + + // Make sure we take the shorter of the two possible paths. + double mp = (quatf.Minus(quat0)).Magnitude(); + double mm = (quatf.Plus(quat0)).Magnitude(); + if(mp > mm) { + quatf = quatf.ScaledBy(-1); + mp = mm; + } + + // Animate transition, unless it's a tiny move. + SDWORD dt = (mp < 0.01) ? (-20) : (SDWORD)(100 + 1000*mp); + SDWORD tn, t0 = GetMilliseconds(); + double s = 0; + do { + offset = (offset0.ScaledBy(1 - s)).Plus(offsetf.ScaledBy(s)); + Quaternion quat = (quat0.ScaledBy(1 - s)).Plus(quatf.ScaledBy(s)); + quat = quat.WithMagnitude(1); + + projRight = quat.RotationU(); + projUp = quat.RotationV(); + PaintGraphics(); + + tn = GetMilliseconds(); + s = (tn - t0)/((double)dt); + } while((tn - t0) < dt); + + projRight = quatf.RotationU(); + projUp = quatf.RotationV(); + offset = offsetf; + InvalidateGraphics(); +} + void GraphicsWindow::MenuView(int id) { switch(id) { case MNU_ZOOM_IN: @@ -137,69 +174,6 @@ void GraphicsWindow::MenuView(int id) { case MNU_ZOOM_TO_FIT: break; - case MNU_LOCK_VIEW: - SS.GW.viewLocked = !SS.GW.viewLocked; - SS.GW.EnsureValidActives(); - break; - - case MNU_ORIENT_ONTO: { - SS.GW.GroupSelection(); - Entity *e = NULL; - if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) { - e = SS.GetEntity(SS.GW.gs.entity[0]); - } else if(SS.GW.activeCsys.v != Entity::NO_CSYS.v) { - e = SS.GetEntity(SS.GW.activeCsys); - } - if(e) { - // A quaternion with our original rotation - Quaternion quat0 = Quaternion::MakeFrom( - SS.GW.projRight, SS.GW.projUp); - // And with our final rotation - Vector pr, pu; - e->Csys2dGetBasisVectors(&pr, &pu); - Quaternion quatf = Quaternion::MakeFrom(pr, pu); - // Make sure we take the shorter of the two possible paths. - double mp = (quatf.Minus(quat0)).Magnitude(); - double mm = (quatf.Plus(quat0)).Magnitude(); - if(mp > mm) { - quatf = quatf.ScaledBy(-1); - mp = mm; - } - - // And also get the offsets. - Vector offset0 = SS.GW.offset; - Vector offsetf = SS.GetEntity(e->assoc[0])->PointGetCoords(); - - // Animate transition, unless it's a tiny move. - SDWORD dt = (mp < 0.01) ? (-20) : (SDWORD)(100 + 1000*mp); - SDWORD tn, t0 = GetMilliseconds(); - double s = 0; - do { - SS.GW.offset = - (offset0.ScaledBy(1 - s)).Plus(offsetf.ScaledBy(s)); - Quaternion quat = - (quat0.ScaledBy(1 - s)).Plus(quatf.ScaledBy(s)); - quat = quat.WithMagnitude(1); - SS.GW.projRight = quat.RotationU(); - SS.GW.projUp = quat.RotationV(); - PaintGraphics(); - - tn = GetMilliseconds(); - s = (tn - t0)/((double)dt); - } while((tn - t0) < dt); - SS.GW.projRight = pr; - SS.GW.projUp = pu; - SS.GW.offset = offsetf; - - SS.GW.hover.Clear(); - SS.GW.ClearSelection(); - InvalidateGraphics(); - } else { - Error("Select plane or coordinate system before orienting."); - } - break; - } - case MNU_UNITS_MM: SS.GW.viewUnits = UNIT_MM; SS.GW.EnsureValidActives(); @@ -245,7 +219,6 @@ void GraphicsWindow::EnsureValidActives(void) { CheckMenuById(MNU_SEL_CSYS, !in3d); // And update the checked state for various menus - CheckMenuById(MNU_LOCK_VIEW, viewLocked); switch(viewUnits) { case UNIT_MM: case UNIT_INCHES: @@ -315,19 +288,30 @@ void GraphicsWindow::MenuEdit(int id) { void GraphicsWindow::MenuRequest(int id) { char *s; switch(id) { - case MNU_SEL_CSYS: + case MNU_SEL_CSYS: { SS.GW.GroupSelection(); if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) { SS.GW.activeCsys = SS.GW.gs.entity[0]; SS.GW.ClearSelection(); - } else { + } + + if(SS.GW.activeCsys.v == Entity::NO_CSYS.v) { Error("Select 2d coordinate system (e.g., the XY plane) " "before locking on."); + break; } + // Align the view with the selected csys + Entity *e = SS.GetEntity(SS.GW.activeCsys); + Vector pr, pu; + e->Csys2dGetBasisVectors(&pr, &pu); + Quaternion quatf = Quaternion::MakeFrom(pr, pu); + Vector offsetf = SS.GetEntity(e->assoc[0])->PointGetCoords(); + SS.GW.AnimateOnto(quatf, offsetf); + SS.GW.EnsureValidActives(); SS.TW.Show(); break; - + } case MNU_NO_CSYS: SS.GW.activeCsys = Entity::NO_CSYS; SS.GW.EnsureValidActives(); @@ -376,11 +360,11 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, double dy = (y - orig.mouse.y) / scale; // When the view is locked, permit only translation (pan). - if(!(shiftDown || ctrlDown) || viewLocked) { + if(!(shiftDown || ctrlDown)) { offset.x = orig.offset.x + dx*projRight.x + dy*projUp.x; offset.y = orig.offset.y + dx*projRight.y + dy*projUp.y; offset.z = orig.offset.z + dx*projRight.z + dy*projUp.z; - } else if(ctrlDown && !viewLocked) { + } else if(ctrlDown) { double theta = atan2(orig.mouse.y, orig.mouse.x); theta -= atan2(y, x); @@ -389,7 +373,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, projUp = orig.projUp.RotatedAbout(normal, theta); NormalizeProjectionVectors(); - } else if(!viewLocked) { + } else { double s = 0.3*(PI/180); // degrees per pixel projRight = orig.projRight.RotatedAbout(orig.projUp, -s*dx); projUp = orig.projUp.RotatedAbout(orig.projRight, s*dy); diff --git a/sketch.cpp b/sketch.cpp index ff5077f..cc1335c 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -31,16 +31,22 @@ void Group::Draw(void) { memset(&poly, 0, sizeof(poly)); SEdge error; if(edges.AssemblePolygon(&poly, &error)) { - glxColor4d(0, 0, 1, 0.15); + glxColor4d(0, 0, 1, 0.1); glxFillPolygon(&poly); } else { - glxColor4d(1, 0, 0, 0.3); + glxColor4d(1, 0, 0, 0.2); glLineWidth(10); glBegin(GL_LINES); glxVertex3v(error.a); glxVertex3v(error.b); glEnd(); glLineWidth(1); + glxColor3d(1, 0, 0); + glPushMatrix(); + glxTranslatev(error.b); + glxOntoCsys(SS.GW.projRight, SS.GW.projUp); + glxWriteText("not closed contour!"); + glPopMatrix(); } poly.Clear(); } diff --git a/solvespace.cpp b/solvespace.cpp index ac69617..1967113 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -12,8 +12,9 @@ void SolveSpace::Init(char *cmdLine) { TW.Init(); GW.Init(); - TW.Show(); GenerateAll(); + + TW.Show(); } void SolveSpace::GenerateAll(void) { @@ -158,6 +159,7 @@ void SolveSpace::MenuFile(int id) { SS.GenerateAll(); SS.GW.Init(); SS.TW.Init(); + SS.TW.Show(); break; case GraphicsWindow::MNU_OPEN: diff --git a/textwin.cpp b/textwin.cpp index 9a90071..0467bf7 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -3,18 +3,17 @@ #define COLOR_BG_HEADER RGB(50, 20, 50) const TextWindow::Color TextWindow::colors[] = { - { RGB(255, 255, 255), COLOR_BG_DEFAULT, }, // 0 + { 'd', RGB(255, 255, 255), COLOR_BG_DEFAULT, }, // default + { 'l', RGB(100, 100, 255), COLOR_BG_DEFAULT, }, // link - { RGB(170, 0, 0), COLOR_BG_HEADER, }, // 1 hidden label - { RGB( 40, 255, 40), COLOR_BG_HEADER, }, // 2 shown label - { RGB(200, 200, 0), COLOR_BG_HEADER, }, // 3 mixed label - { RGB(255, 200, 40), COLOR_BG_HEADER, }, // 4 yellow text - { RGB(255, 255, 255), COLOR_BG_HEADER, }, // 5 white text - { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 6 - { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 7 + // These are for the header + { 'D', RGB(255, 255, 255), COLOR_BG_HEADER, }, // default + { 'H', RGB(170, 0, 0), COLOR_BG_HEADER, }, // hidden + { 'S', RGB( 40, 255, 40), COLOR_BG_HEADER, }, // shown + { 'M', RGB(200, 200, 0), COLOR_BG_HEADER, }, // mixed h/s + { 'T', RGB(255, 200, 40), COLOR_BG_HEADER, }, // title - { RGB(255, 255, 255), COLOR_BG_DEFAULT, }, // 8 title - { RGB(100, 100, 255), COLOR_BG_DEFAULT, }, // 9 link + { 0, 0, 0 }, }; void TextWindow::Init(void) { @@ -29,7 +28,7 @@ void TextWindow::ClearScreen(void) { for(i = 0; i < MAX_ROWS; i++) { for(j = 0; j < MAX_COLS; j++) { text[i][j] = ' '; - meta[i][j].color = COLOR_DEFAULT; + meta[i][j].color = 'd'; meta[i][j].link = NOT_A_LINK; } } @@ -51,7 +50,7 @@ void TextWindow::Printf(char *fmt, ...) { meta[r][c].link = NOT_A_LINK; } - int color = COLOR_DEFAULT; + int color = 'd'; int link = NOT_A_LINK; DWORD data = 0; LinkFunction *f = NULL; @@ -81,7 +80,7 @@ void TextWindow::Printf(char *fmt, ...) { break; } case 'E': - color = COLOR_DEFAULT; + color = 'd'; link = NOT_A_LINK; data = 0; f = NULL; @@ -93,9 +92,9 @@ void TextWindow::Printf(char *fmt, ...) { if(*fmt == 'p') { color = va_arg(vl, int); } else { - color = *fmt - '0'; + color = *fmt; } - if(color < 0 || color >= arraylen(colors)) color = 0; + if(color < 0 || color > 255) color = 0; break; case 'L': @@ -155,15 +154,11 @@ void TextWindow::Show(void) { } else { switch(shown->screen) { default: - shown->screen = SCREEN_ALL_GROUPS; + shown->screen = SCREEN_LIST_OF_GROUPS; // fall through - case SCREEN_ALL_GROUPS: - ShowAllGroups(); - break; - - case SCREEN_REQUESTS_IN_GROUP: - ShowRequestsInGroup(); - break; + case SCREEN_LIST_OF_GROUPS: ShowListOfGroups(); break; + case SCREEN_GROUP_INFO: ShowGroupInfo(); break; + case SCREEN_REQUEST_INFO: ShowRequestInfo(); break; } } InvalidateText(); @@ -181,7 +176,7 @@ void TextWindow::ScreenNavigation(int link, DWORD v) { default: case 'h': SS.TW.OneScreenForward(); - SS.TW.shown->screen = SCREEN_ALL_GROUPS; + SS.TW.shown->screen = SCREEN_LIST_OF_GROUPS; break; case 'b': @@ -205,7 +200,7 @@ void TextWindow::ShowHeader(void) { SS.GW.EnsureValidActives(); if(SS.GW.pendingDescription) { - Printf(" %C4 group:%s", + Printf(" %CT group:%s", SS.group.FindById(SS.GW.activeGroup)->DescriptionString()); } else { // Navigation buttons @@ -215,7 +210,7 @@ void TextWindow::ShowHeader(void) { } else { cd = SS.GetEntity(SS.GW.activeCsys)->DescriptionString(); } - Printf(" %Lb%f<<%E %Lh%fhome%E %C4 csys:%C5 %s", + Printf(" %Lb%f<<%E %Lh%fhome%E %CT csys:%CD %s", (DWORD)(&TextWindow::ScreenNavigation), (DWORD)(&TextWindow::ScreenNavigation), cd); @@ -223,27 +218,27 @@ void TextWindow::ShowHeader(void) { int datumColor; if(SS.GW.show2dCsyss && SS.GW.showAxes && SS.GW.showPoints) { - datumColor = COLOR_MEANS_SHOWN; + datumColor = 'S'; // shown } else if(!(SS.GW.show2dCsyss || SS.GW.showAxes || SS.GW.showPoints)) { - datumColor = COLOR_MEANS_HIDDEN; + datumColor = 'H'; // hidden } else { - datumColor = COLOR_MEANS_MIXED; + datumColor = 'M'; // mixed } -#define hs(b) ((b) ? COLOR_MEANS_SHOWN : COLOR_MEANS_HIDDEN) - Printf("%C4show: " - "%Cp%Ll%D%f2d-csys%E%C4 " - "%Cp%Ll%D%faxes%E%C4 " - "%Cp%Ll%D%fpoints%E%C4 " - "%Cp%Ll%fany-datum%E%C4", +#define hs(b) ((b) ? 'S' : 'H') + Printf("%CTshow: " + "%Cp%Ll%D%f2d-csys%E%CT " + "%Cp%Ll%D%faxes%E%CT " + "%Cp%Ll%D%fpoints%E%CT " + "%Cp%Ll%fany-datum%E%CT", hs(SS.GW.show2dCsyss), (DWORD)&(SS.GW.show2dCsyss), &(SS.GW.ToggleBool), hs(SS.GW.showAxes), (DWORD)&(SS.GW.showAxes), &(SS.GW.ToggleBool), hs(SS.GW.showPoints), (DWORD)&(SS.GW.showPoints), &(SS.GW.ToggleBool), datumColor, &(SS.GW.ToggleAnyDatumShown) ); - Printf("%C4 " - "%Cp%Ll%D%fall-groups%E%C4 " - "%Cp%Ll%D%fconstraints%E%C4", + Printf("%CT " + "%Cp%Ll%D%fall-groups%E%CT " + "%Cp%Ll%D%fconstraints%E%CT", hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), &(SS.GW.ToggleBool), hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), @@ -251,56 +246,68 @@ void TextWindow::ShowHeader(void) { ); } -void TextWindow::ShowAllGroups(void) { - Printf("%C8[[all groups in sketch follow]]%E"); +void TextWindow::ShowListOfGroups(void) { + Printf("%Cd[[all groups in sketch follow]]%E"); int i; - for(i = 0; i <= SS.group.n; i++) { - DWORD v; + for(i = 0; i < SS.group.n; i++) { char *s; - if(i == SS.group.n) { - s = "all requests from all groups"; - v = 0; - } else { - Group *g = &(SS.group.elem[i]); - s = g->DescriptionString(); - v = g->h.v; - } - Printf(" %C9%Ll%D%f%s%E", v, (DWORD)(&TextWindow::ScreenSelectGroup), s); + Group *g = &(SS.group.elem[i]); + s = g->DescriptionString(); + Printf(" %Cl%Ll%D%f%s%E", + g->h.v, (DWORD)(&TextWindow::ScreenSelectGroup), s); } } void TextWindow::ScreenSelectGroup(int link, DWORD v) { SS.TW.OneScreenForward(); - SS.TW.shown->screen = SCREEN_REQUESTS_IN_GROUP; + SS.TW.shown->screen = SCREEN_GROUP_INFO; SS.TW.shown->group.v = v; SS.TW.Show(); } -void TextWindow::ShowRequestsInGroup(void) { - if(shown->group.v == 0) { - Printf("%C8[[requests in all groups]]%E"); +void TextWindow::ScreenSelectRequest(int link, DWORD v) { + SS.TW.OneScreenForward(); + + SS.TW.shown->screen = SCREEN_REQUEST_INFO; + SS.TW.shown->request.v = v; + + SS.TW.Show(); +} +void TextWindow::ShowGroupInfo(void) { + Group *g = SS.group.FindById(shown->group); + if(SS.GW.activeGroup.v == shown->group.v) { + Printf("%Cd[[this is the active group]]"); + } else if(shown->group.v == Group::HGROUP_REFERENCES.v) { + Printf("%Cd[[this group contains the references]]"); } else { - Group *g = SS.group.FindById(shown->group); - if(SS.GW.activeGroup.v == shown->group.v) { - Printf("%C8[[this is the active group]]"); - } else if(shown->group.v == Group::HGROUP_REFERENCES.v) { - Printf("%C8[[this group contains the references]]"); - } else { - Printf("%C8[[not active; %C9%Llactivate this group%E%C8]]"); - } - Printf("%C8[[requests in group %s]]%E", g->DescriptionString()); + Printf("%Cd[[not active; %Cl%Llactivate this group%E%Cd]]"); } + Printf("%Cd[[requests in group %s]]%E", g->DescriptionString()); int i; for(i = 0; i < SS.request.n; i++) { Request *r = &(SS.request.elem[i]); - if(r->group.v == shown->group.v || shown->group.v == 0) { + if(r->group.v == shown->group.v) { char *s = r->DescriptionString(); - Printf(" %s", s); + Printf(" %Cl%Ll%D%f%s%E", + r->h.v, (DWORD)(&TextWindow::ScreenSelectRequest), s); } } } +void TextWindow::ShowRequestInfo(void) { + Request *r = SS.GetRequest(shown->request); + + char *s; + switch(r->type) { + case Request::CSYS_2D: s = "2d coordinate system"; break; + case Request::DATUM_POINT: s = "datum point"; break; + case Request::LINE_SEGMENT: s = "line segment"; break; + default: oops(); + } + Printf("%Cd[[request for %s]]%E", s); +} + diff --git a/ui.h b/ui.h index 02fc1f8..bc74738 100644 --- a/ui.h +++ b/ui.h @@ -13,14 +13,11 @@ public: static const int COLOR_BG_DEFAULT = RGB( 15, 15, 0); typedef struct { + char c; int fg; int bg; } Color; static const Color colors[]; - static const int COLOR_DEFAULT = 0; - static const int COLOR_MEANS_HIDDEN = 1; - static const int COLOR_MEANS_SHOWN = 2; - static const int COLOR_MEANS_MIXED = 3; // The rest of the window, text displayed in response to typed commands; // some of this might do something if you click on it. @@ -45,11 +42,14 @@ public: void Show(void); // State for the screen that we are showing in the text window. - static const int SCREEN_ALL_GROUPS = 0; - static const int SCREEN_REQUESTS_IN_GROUP = 1; + static const int SCREEN_LIST_OF_GROUPS = 0; + static const int SCREEN_GROUP_INFO = 1; + static const int SCREEN_REQUEST_INFO = 2; + static const int SCREEN_ENTIY_INFO = 3; typedef struct { - int screen; - hGroup group; + int screen; + hGroup group; + hRequest request; } ShownState; static const int HISTORY_LEN = 16; ShownState showns[HISTORY_LEN]; @@ -60,11 +60,14 @@ public: void ShowHeader(void); // These are self-contained screens, that show some information about // the sketch. - void ShowAllGroups(void); - void ShowRequestsInGroup(void); + void ShowListOfGroups(void); + void ShowGroupInfo(void); + void ShowRequestInfo(void); + void ShowEntityInfo(void); void OneScreenForward(void); static void ScreenSelectGroup(int link, DWORD v); + static void ScreenSelectRequest(int link, DWORD v); static void ScreenNavigation(int link, DWORD v); }; @@ -84,8 +87,6 @@ public: MNU_ZOOM_IN, MNU_ZOOM_OUT, MNU_ZOOM_TO_FIT, - MNU_ORIENT_ONTO, - MNU_LOCK_VIEW, MNU_UNSELECT_ALL, MNU_UNITS_INCHES, MNU_UNITS_MM, @@ -133,10 +134,10 @@ public: Vector projUp; Point2d mouse; } orig; - bool viewLocked; void NormalizeProjectionVectors(void); Point2d ProjectPoint(Vector p); + void AnimateOnto(Quaternion quatf, Vector offsetf); typedef enum { UNIT_MM = 0, diff --git a/win32/w32main.cpp b/win32/w32main.cpp index 2d2544e..6295407 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -16,12 +16,18 @@ #define TEXT_HEIGHT 18 #define TEXT_WIDTH 9 +// There's a half-line offset between the header and the rest of the window +#define OFFSET_LINE 3 +#define OFFSET_HEIGHT 9 + HINSTANCE Instance; HWND TextWnd; HWND TextWndScrollBar; int TextWndScrollPos; int TextWndRows; +COLORREF BgColor[256]; +COLORREF FgColor[256]; HWND GraphicsWnd; HWND GraphicsEditControl; @@ -83,6 +89,15 @@ void MemFree(void *p) { free(p); } static void PaintTextWnd(HDC hdc) { + // Generate the color table. + int i; + for(i = 0; SS.TW.colors[i].c != 0; i++) { + int c = SS.TW.colors[i].c; + if(c < 0 || c > 255) oops(); + BgColor[c] = SS.TW.colors[i].bg; + FgColor[c] = SS.TW.colors[i].fg; + } + RECT rect; GetClientRect(TextWnd, &rect); @@ -122,10 +137,9 @@ static void PaintTextWnd(HDC hdc) if(r >= SS.TW.MAX_ROWS) continue; for(c = 0; c < SS.TW.MAX_COLS; c++) { - char v = '0' + (c % 10); int color = SS.TW.meta[r][c].color; - SetTextColor(backDc, SS.TW.colors[color].fg); - SetBkColor(backDc, SS.TW.colors[color].bg); + SetTextColor(backDc, FgColor[color]); + SetBkColor(backDc, BgColor[color]); if(SS.TW.meta[r][c].link) { SelectObject(backDc, LinkFont); @@ -134,9 +148,10 @@ static void PaintTextWnd(HDC hdc) } int x = 4 + c*TEXT_WIDTH; - int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 + (r >= 3 ? 9 : 0); + int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 + + (r >= OFFSET_LINE ? OFFSET_HEIGHT : 0); - HBRUSH b = CreateSolidBrush(SS.TW.colors[color].bg); + HBRUSH b = CreateSolidBrush(BgColor[color]); RECT a; a.left = x; a.right = x+TEXT_WIDTH; a.top = y; a.bottom = y+TEXT_HEIGHT; @@ -242,6 +257,10 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) int x = LOWORD(lParam); int y = HIWORD(lParam); + if(y >= TEXT_HEIGHT*OFFSET_LINE) { + y -= OFFSET_HEIGHT; + } + // Find the corresponding character in the text buffer int r = (y / TEXT_HEIGHT); int c = (x / TEXT_WIDTH);