From 6c63d9c8cbf3b1441990215dac0a0452f7e751e2 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Sat, 12 Apr 2008 06:12:26 -0800 Subject: [PATCH] Get rid of the command line from the text window; we'll say that's just for display, and any text entry will happen via some floating text box, same as entering a dimension on the sketch. Add the hover and selection mechanism, which now seems to work. Still not clear how to do imported parts, for assemblies and hierarchy. The handle formats may still have to change. [git-p4: depot-paths = "//depot/solvespace/": change = 1662] --- cmdline.cpp | 184 ++++++++++++++++++++++++++-------------------- dsc.h | 8 +- entity.cpp | 67 +++++++++++------ expr.h | 27 ++++--- graphicswin.cpp | 109 ++++++++++++++++++++++++++- sketch.cpp | 53 ++++++++++++- sketch.h | 22 ++++-- solvespace.h | 2 +- ui.h | 55 +++++++++----- util.cpp | 45 ++++++++++++ win32/w32main.cpp | 31 +------- 11 files changed, 433 insertions(+), 170 deletions(-) diff --git a/cmdline.cpp b/cmdline.cpp index 49612ec..9f3595d 100644 --- a/cmdline.cpp +++ b/cmdline.cpp @@ -1,20 +1,27 @@ #include "solvespace.h" #include +#define COLOR_BG_HEADER RGB(50, 20, 50) const TextWindow::Color TextWindow::colors[] = { - { COLOR_FG_DEFAULT, COLOR_BG_DEFAULT, }, // 0 - { RGB(170, 0, 0), COLOR_BG_DEFAULT, }, // 1 - { RGB( 40, 255, 40), COLOR_BG_DEFAULT, }, // 2 - { RGB(200, 200, 0), COLOR_BG_DEFAULT, }, // 3 - { RGB(255, 200, 40), COLOR_BG_DEFAULT, }, // 4 - { RGB(255, 40, 40), COLOR_BG_DEFAULT, }, // 5 - { RGB( 0, 255, 255), COLOR_BG_DEFAULT, }, // 6 - { RGB(255, 0, 255), COLOR_BG_DEFAULT, }, // 7 + { RGB(255, 255, 255), COLOR_BG_DEFAULT, }, // 0 + + { 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 header text + { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 5 + { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 6 + { RGB( 0, 0, 0), COLOR_BG_DEFAULT, }, // 7 + + { RGB(255, 255, 255), COLOR_BG_DEFAULT, }, // 8 title + { RGB(100, 100, 255), COLOR_BG_DEFAULT, }, // 9 link }; void TextWindow::Init(void) { + memset(this, 0, sizeof(*this)); + shown = &(showns[shownIndex]); + ClearScreen(); - ClearCommand(); } void TextWindow::ClearScreen(void) { @@ -22,7 +29,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_NORMAL; + meta[i][j].color = COLOR_DEFAULT; meta[i][j].link = NOT_A_LINK; } } @@ -44,7 +51,7 @@ void TextWindow::Printf(char *fmt, ...) { meta[r][c].link = NOT_A_LINK; } - int color = COLOR_NORMAL; + int color = COLOR_DEFAULT; int link = NOT_A_LINK; DWORD data = 0; LinkFunction *f = NULL; @@ -74,7 +81,7 @@ void TextWindow::Printf(char *fmt, ...) { break; } case 'E': - color = COLOR_NORMAL; + color = COLOR_DEFAULT; link = NOT_A_LINK; data = 0; f = NULL; @@ -126,64 +133,69 @@ void TextWindow::Printf(char *fmt, ...) { fmt++; } + while(c < MAX_COLS) { + meta[r][c].color = color; + c++; + } done: va_end(vl); } -void TextWindow::ClearCommand(void) { - int j; - for(j = 0; j < MAX_COLS; j++) { - cmd[j] = ' '; - } - memcpy(cmd, "+> ", 3); - cmdLen = 0; - cmdInsert = 3; -} - -void TextWindow::ProcessCommand(char *cmd) -{ - Printf("%C2command:%E '%s' done %C3(green)%E %C5%LaLink%E", cmd); -} - -void TextWindow::KeyPressed(int c) { - if(cmdLen >= MAX_COLS - 10) { - ClearCommand(); - return; - } - - if(c == '\n' || c == '\r') { - 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; - memmove(cmd+cmdInsert-1, cmd+cmdInsert, MAX_COLS-cmdInsert); - cmdLen--; - cmdInsert--; - } else { - cmd[cmdInsert] = c; - cmdInsert++; - cmdLen++; - } -} - void TextWindow::Show(void) { - ShowRequestList(); + ShowHeader(); + switch(shown->screen) { + default: + shown->screen = SCREEN_GROUP_LIST; + // fall through + case SCREEN_GROUP_LIST: + ShowGroupList(); + break; + case SCREEN_REQUEST_LIST: + ShowRequestList(); + break; + } InvalidateText(); } +void TextWindow::OneScreenForward(void) { + SS.TW.shownIndex++; + if(SS.TW.shownIndex >= HISTORY_LEN) SS.TW.shownIndex = 0; + SS.TW.shown = &(SS.TW.showns[SS.TW.shownIndex]); + history++; +} + +void TextWindow::ScreenNavigaton(int link, DWORD v) { + switch(link) { + default: + case 'h': + SS.TW.OneScreenForward(); + SS.TW.shown->screen = SCREEN_GROUP_LIST; + break; + + case 'b': + if(SS.TW.history > 0) { + SS.TW.shownIndex--; + if(SS.TW.shownIndex < 0) SS.TW.shownIndex = (HISTORY_LEN-1); + SS.TW.shown = &(SS.TW.showns[SS.TW.shownIndex]); + SS.TW.history--; + } + break; + + case 'f': + SS.TW.OneScreenForward(); + break; + } + SS.TW.Show(); +} void TextWindow::ShowHeader(void) { ClearScreen(); + Printf(" %Lb%f<<%E %Lh%fhome%E", + (DWORD)(&TextWindow::ScreenNavigaton), + (DWORD)(&TextWindow::ScreenNavigaton)); + int datumColor; if(SS.GW.show2dCsyss && SS.GW.showAxes && SS.GW.showPoints) { datumColor = COLOR_MEANS_SHOWN; @@ -194,19 +206,19 @@ void TextWindow::ShowHeader(void) { } #define hs(b) ((b) ? COLOR_MEANS_SHOWN : COLOR_MEANS_HIDDEN) - Printf("show: " - "%Cp%Ll%D%f2d-csys%E " - "%Cp%Ll%D%faxes%E " - "%Cp%Ll%D%fpoints%E " - "%Cp%Ll%fany-datum%E", + 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", 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(" " - "%Cp%Ll%D%fall-groups%E " - "%Cp%Ll%D%fconstraints%E", + Printf("%C4 " + "%Cp%Ll%D%fall-groups%E%C4 " + "%Cp%Ll%D%fconstraints%E%C4", hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), &(SS.GW.ToggleBool), hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), @@ -215,32 +227,46 @@ void TextWindow::ShowHeader(void) { } void TextWindow::ShowGroupList(void) { - ShowHeader(); - - Printf("%C4[[all groups in sketch]]%E"); + Printf("%C8[[click group to view requests]]%E"); int i; - for(i = 0; i < SS.group.elems; i++) { - Group *g = &(SS.group.elem[i].t); - if(g->name.str[0]) { - Printf(" %s", g->name.str); + for(i = 0; i <= SS.group.elems; i++) { + DWORD v; + char *s; + if(i == SS.group.elems) { + s = "all requests from all groups"; + v = 0; } else { - Printf(" unnamed"); + Group *g = &(SS.group.elem[i].t); + s = g->DescriptionString(); + v = g->h.v; } + Printf(" %C9%Ll%D%f%s%E", v, (DWORD)(&TextWindow::ScreenSelectGroup), s); } } +void TextWindow::ScreenSelectGroup(int link, DWORD v) { + SS.TW.OneScreenForward(); + + SS.TW.shown->screen = SCREEN_REQUEST_LIST; + SS.TW.shown->group.v = v; + + SS.TW.Show(); +} void TextWindow::ShowRequestList(void) { - ShowHeader(); + if(shown->group.v == 0) { + Printf("%C8[[requests in all groups]]%E"); + } else { + Group *g = SS.group.FindById(shown->group); + Printf("%C8[[requests in group %s]]%E", g->DescriptionString()); + } - Printf("%C4[[all requests in sketch]]%E"); int i; for(i = 0; i < SS.request.elems; i++) { Request *r = &(SS.request.elem[i].t); - if(r->name.str[0]) { - Printf(" %s", r->name.str); - } else { - Printf(" unnamed"); + if(r->group.v == shown->group.v || shown->group.v == 0) { + char *s = r->DescriptionString(); + Printf(" %s", s); } } } diff --git a/dsc.h b/dsc.h index 91d91da..9b5b4c1 100644 --- a/dsc.h +++ b/dsc.h @@ -19,7 +19,7 @@ public: Vector Normal(int which); Vector RotatedAbout(Vector axis, double theta); double Magnitude(void); - Vector ScaledBy(double v); + Vector ScaledBy(double s); // Call a rotation matrix [ u' v' n' ]'; this returns the first and // second rows, where that matrix is generated by the given quaternion @@ -31,6 +31,12 @@ public: class Point2d { public: double x, y; + + Point2d Plus(Point2d b); + Point2d Minus(Point2d b); + Point2d ScaledBy(double s); + double DistanceTo(Point2d p); + double DistanceToLine(Point2d p0, Point2d dp, bool segment); }; template diff --git a/entity.cpp b/entity.cpp index 2716b2f..884cf57 100644 --- a/entity.cpp +++ b/entity.cpp @@ -1,13 +1,36 @@ #include "solvespace.h" -void Entity::LineDrawHitTest(Vector a, Vector b) { - glBegin(GL_LINE_STRIP); - glxVertex3v(a); - glxVertex3v(b); - glEnd(); +void Entity::LineDrawOrGetDistance(Vector a, Vector b) { + if(dogd.drawing) { + glBegin(GL_LINE_STRIP); + glxVertex3v(a); + glxVertex3v(b); + glEnd(); + } else { + Point2d ap = SS.GW.ProjectPoint(a); + Point2d bp = SS.GW.ProjectPoint(b); + + double d = dogd.mp.DistanceToLine(ap, bp.Minus(ap), true); + dogd.dmin = min(dogd.dmin, d); + } } void Entity::Draw(void) { + dogd.drawing = true; + DrawOrGetDistance(); +} + +double Entity::GetDistance(Point2d mp) { + dogd.drawing = false; + dogd.mp = mp; + dogd.dmin = 1e12; + + DrawOrGetDistance(); + + return dogd.dmin; +} + +void Entity::DrawOrGetDistance(void) { switch(type) { case CSYS_2D: { if(!SS.GW.show2dCsyss) break; @@ -15,7 +38,7 @@ void Entity::Draw(void) { Vector p; double a, b, c, d; - SS.point.FindById(point(16))->GetInto(&p); + p = SS.point.FindById(point(16))->GetCoords(); a = SS.param.FindById(param(0))->val; b = SS.param.FindById(param(1))->val; c = SS.param.FindById(param(2))->val; @@ -26,28 +49,28 @@ void Entity::Draw(void) { double s = (min(SS.GW.width, SS.GW.height))*0.4; - Vector pp = (p.Plus(u)).Plus(v); - Vector pm = (p.Plus(u)).Minus(v); - Vector mm = (p.Minus(u)).Minus(v); - Vector mp = (p.Minus(u)).Plus(v); + Vector pp = p.Plus (u).Plus (v); + Vector pm = p.Plus (u).Minus(v); + Vector mm = p.Minus(u).Minus(v); + Vector mp = p.Minus(u).Plus (v); pp = pp.ScaledBy(s); pm = pm.ScaledBy(s); mm = mm.ScaledBy(s); mp = mp.ScaledBy(s); - LineDrawHitTest(pp, pm); - LineDrawHitTest(pm, mm); - LineDrawHitTest(mm, mp); - LineDrawHitTest(mp, pp); + LineDrawOrGetDistance(pp, pm); + LineDrawOrGetDistance(pm, mm); + LineDrawOrGetDistance(mm, mp); + LineDrawOrGetDistance(mp, pp); - Request *r = SS.request.FindById(this->request()); - glPushMatrix(); - glxTranslatev(mm); - glxOntoCsys(u, v); - glxWriteText(r->name.str); - glPopMatrix(); - - glEnd(); + if(dogd.drawing) { + Request *r = SS.request.FindById(this->request()); + glPushMatrix(); + glxTranslatev(mm); + glxOntoCsys(u, v); + glxWriteText(r->DescriptionString()); + glPopMatrix(); + } break; } default: diff --git a/expr.h b/expr.h index dc6ba8a..a8ce3da 100644 --- a/expr.h +++ b/expr.h @@ -12,16 +12,21 @@ public: // if we know that the param table won't move around) static const int PARAM_PTR = 1; - static const int CONSTANT = 10; - static const int PLUS = 21; - static const int MINUS = 22; - static const int TIMES = 23; - static const int DIV = 24; - static const int NEGATE = 25; - static const int SQRT = 26; - static const int SQUARE = 27; - static const int SIN = 28; - static const int COS = 29; + // These are used only for user-entered expressions. + static const int POINT = 10; + static const int ENTITY = 11; + + static const int CONSTANT = 20; + + static const int PLUS = 100; + static const int MINUS = 101; + static const int TIMES = 102; + static const int DIV = 103; + static const int NEGATE = 104; + static const int SQRT = 105; + static const int SQUARE = 106; + static const int SIN = 107; + static const int COS = 108; int op; Expr *a; @@ -29,6 +34,8 @@ public: union { hParam parh; double *parp; + hPoint point; + hEntity entity; double v; } x; }; diff --git a/graphicswin.cpp b/graphicswin.cpp index 0d536b5..6ca1bb7 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -35,7 +35,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { }; void GraphicsWindow::Init(void) { - offset.x = offset.y = offset.z = 0.9; + memset(this, 0, sizeof(*this)); + + offset.x = offset.y = offset.z = 0; scale = 1; projRight.x = 1; projRight.y = projRight.z = 0; projDown.y = 1; projDown.z = projDown.x = 0; @@ -55,10 +57,23 @@ void GraphicsWindow::NormalizeProjectionVectors(void) { projRight = projRight.ScaledBy(1/projRight.Magnitude()); } +Point2d GraphicsWindow::ProjectPoint(Vector p) { + p = p.Plus(offset); + + Point2d r; + r.x = p.Dot(projRight) * scale; + r.y = p.Dot(projDown) * scale; + return r; +} + void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown) { + Point2d mp = { x, y }; + if(middleDown) { + hover.Clear(); + double dx = (x - orig.mouse.x) / scale; double dy = (y - orig.mouse.y) / scale; @@ -90,6 +105,57 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, orig.mouse.y = y; InvalidateGraphics(); + } else { + // No mouse buttons are pressed. We just need to do our usual hit + // testing, to see if anything ought to be hovered. + Selection s; + HitTestMakeSelection(mp, &s); + if(!s.Equals(&hover)) { + hover = s; + InvalidateGraphics(); + } + } +} + +bool GraphicsWindow::Selection::Equals(Selection *b) { + if(point.v != b->point.v) return false; + if(entity.v != b->entity.v) return false; + return true; +} +bool GraphicsWindow::Selection::IsEmpty(void) { + if(point.v) return false; + if(entity.v) return false; + return true; +} +void GraphicsWindow::Selection::Clear(void) { + point.v = entity.v = 0; +} +void GraphicsWindow::Selection::Draw(void) { + if(point.v) SS.point. FindById(point )->Draw(); + if(entity.v) SS.entity.FindById(entity)->Draw(); +} + +void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) { + int i; + double d, dmin = 1e12; + + dest->point.v = 0; + dest->entity.v = 0; + + for(i = 0; i < SS.entity.elems; i++) { + d = SS.entity.elem[i].t.GetDistance(mp); + if(d < 10 && d < dmin) { + dest->point.v = 0; + dest->entity = SS.entity.elem[i].t.h; + } + } + + for(i = 0; i < SS.point.elems; i++) { + d = SS.point.elem[i].t.GetDistance(mp); + if(d < 10 && d < dmin) { + dest->entity.v = 0; + dest->point = SS.point.elem[i].t.h; + } } } @@ -102,6 +168,27 @@ void GraphicsWindow::MouseMiddleDown(double x, double y) { } void GraphicsWindow::MouseLeftDown(double x, double y) { + // Make sure the hover is up to date. + MouseMoved(x, y, false, false, false, false, false); + + if(!hover.IsEmpty()) { + int i; + for(i = 0; i < MAX_SELECTED; i++) { + if(selection[i].Equals(&hover)) { + selection[i].Clear(); + goto done; + } + } + for(i = 0; i < MAX_SELECTED; i++) { + if(selection[i].IsEmpty()) { + selection[i] = hover; + goto done; + } + } + // I guess we ran out of slots, oh well. +done: + InvalidateGraphics(); + } } void GraphicsWindow::MouseScroll(double x, double y, int delta) { @@ -176,11 +263,29 @@ void GraphicsWindow::Paint(int w, int h) { glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glColor3f(1, 1, 1); int i; + + // First, draw the entire scene. + glColor3f(1, 1, 1); for(i = 0; i < SS.entity.elems; i++) { SS.entity.elem[i].t.Draw(); } + glColor3f(0, 0.8f, 0); + for(i = 0; i < SS.point.elems; i++) { + SS.point.elem[i].t.Draw(); + } + + // Then redraw whatever the mouse is hovering over, highlighted. Have + // to disable the depth test, so that we can overdraw. + glDisable(GL_DEPTH_TEST); + glColor3f(1, 1, 0); + hover.Draw(); + + // And finally draw the selection, same mechanism. + glColor3f(1, 0, 0); + for(i = 0; i < MAX_SELECTED; i++) { + selection[i].Draw(); + } } diff --git a/sketch.cpp b/sketch.cpp index 2270fd8..29312ca 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -7,6 +7,16 @@ const hRequest Request::HREQUEST_REFERENCE_XY = { 1 }; const hRequest Request::HREQUEST_REFERENCE_YZ = { 2 }; const hRequest Request::HREQUEST_REFERENCE_ZX = { 3 }; +char *Group::DescriptionString(void) { + static char ret[100]; + if(name.str[0]) { + sprintf(ret, "g%03x-%s", h.v, name.str); + } else { + sprintf(ret, "g%03x-(unnamed)", h.v); + } + return ret; +} + void Request::AddParam(Entity *e, int index) { Param pa; memset(&pa, 0, sizeof(pa)); @@ -67,6 +77,16 @@ c: { } } +char *Request::DescriptionString(void) { + static char ret[100]; + if(name.str[0]) { + sprintf(ret, "r%03x-%s", h.v, name.str); + } else { + sprintf(ret, "r%03x-(unnamed)", h.v); + } + return ret; +} + void Param::ForceTo(double v) { val = v; known = true; @@ -85,16 +105,41 @@ void Point::ForceTo(Vector v) { } } -void Point::GetInto(Vector *v) { +Vector Point::GetCoords(void) { + Vector v; switch(type) { case IN_FREE_SPACE: - v->x = SS.param.FindById(param(0))->val; - v->y = SS.param.FindById(param(1))->val; - v->z = SS.param.FindById(param(2))->val; + v.x = SS.param.FindById(param(0))->val; + v.y = SS.param.FindById(param(1))->val; + v.z = SS.param.FindById(param(2))->val; break; default: oops(); } + + return v; +} + +void Point::Draw(void) { + Vector v = GetCoords(); + + double s = 4; + Vector r = SS.GW.projRight.ScaledBy(4/SS.GW.scale); + Vector d = SS.GW.projDown.ScaledBy(4/SS.GW.scale); + + glBegin(GL_QUADS); + glxVertex3v(v.Plus (r).Plus (d)); + glxVertex3v(v.Plus (r).Minus(d)); + glxVertex3v(v.Minus(r).Minus(d)); + glxVertex3v(v.Minus(r).Plus (d)); + glEnd(); +} + +double Point::GetDistance(Point2d mp) { + Vector v = GetCoords(); + Point2d pp = SS.GW.ProjectPoint(v); + + return pp.DistanceTo(mp); } diff --git a/sketch.h b/sketch.h index 2a5fdfc..d4b054f 100644 --- a/sketch.h +++ b/sketch.h @@ -55,6 +55,8 @@ public: hEntity csys; // or Entity::NO_CSYS, if it's not locked in a 2d csys NameStr name; + + char *DescriptionString(void); }; // A user request for some primitive or derived operation; for example a @@ -83,6 +85,8 @@ public: void AddParam(Entity *e, int index); void Generate(void); + + char *DescriptionString(void); }; class Entity { @@ -104,8 +108,15 @@ public: inline hPoint point(int i) { hPoint r; r.v = ((this->h.v) << 8) | i; return r; } - void LineDrawHitTest(Vector a, Vector b); + struct { + bool drawing; + Point2d mp; + double dmin; + } dogd; // state for drawing or getting distance (for hit testing) + void LineDrawOrGetDistance(Vector a, Vector b); + void DrawOrGetDistance(void); void Draw(void); + double GetDistance(Point2d mp); }; class Param { @@ -137,12 +148,13 @@ public: // The point, in base coordinates. This may be a single parameter, or // it may be a more complex expression if our point is locked in a // 2d csys. - Expr *x(void); - Expr *y(void); - Expr *z(void); + void GetExprs(Expr **x, Expr **y, Expr **z); + Vector GetCoords(void); void ForceTo(Vector v); - void GetInto(Vector *v); + + void Draw(void); + double GetDistance(Point2d mp); }; #endif diff --git a/solvespace.h b/solvespace.h index 248c0e8..7fa847f 100644 --- a/solvespace.h +++ b/solvespace.h @@ -23,8 +23,8 @@ void dbp(char *str, ...); class Expr; #include "dsc.h" -#include "ui.h" #include "sketch.h" +#include "ui.h" #include "expr.h" // From the platform-specific code. diff --git a/ui.h b/ui.h index 1f487b9..cde9272 100644 --- a/ui.h +++ b/ui.h @@ -11,9 +11,6 @@ public: #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); typedef struct { int fg; @@ -25,18 +22,11 @@ public: static const int COLOR_MEANS_SHOWN = 2; static const int COLOR_MEANS_MIXED = 3; - // The line with the user-typed command, that is currently being edited. - char cmd[MAX_COLS]; - int cmdInsert; - int cmdLen; - // The rest of the window, text displayed in response to typed commands; // some of this might do something if you click on it. static const int NOT_A_LINK = 0; - static const int COLOR_NORMAL = 0; - BYTE text[MAX_ROWS][MAX_COLS]; typedef void LinkFunction(int link, DWORD v); struct { @@ -52,21 +42,29 @@ public: void Printf(char *fmt, ...); void ClearScreen(void); - 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); - void Show(void); + // State for the screen that we are showing in the text window. + static const int SCREEN_GROUP_LIST = 0; + static const int SCREEN_REQUEST_LIST = 1; + typedef struct { + int screen; + hGroup group; + } ShownState; + static const int HISTORY_LEN = 16; + ShownState showns[HISTORY_LEN]; + int shownIndex; + int history; + ShownState *shown; + void ShowHeader(void); // These are self-contained screens, that show some information about // the sketch. void ShowGroupList(void); void ShowRequestList(void); + void OneScreenForward(void); + static void ScreenSelectGroup(int link, DWORD v); + static void ScreenNavigaton(int link, DWORD v); }; class GraphicsWindow { @@ -81,6 +79,8 @@ public: } MenuEntry; static const MenuEntry menu[]; + void Init(void); + // The width and height (in pixels) of the window. double width, height; // These parameters define the map from 2d screen coordinates to the @@ -97,9 +97,26 @@ public: Point2d mouse; } orig; - void Init(void); void NormalizeProjectionVectors(void); + Point2d ProjectPoint(Vector p); + // The current selection. + class Selection { + public: + hPoint point; + hEntity entity; + + void Draw(void); + + void Clear(void); + bool IsEmpty(void); + bool Equals(Selection *b); + }; + Selection hover; + static const int MAX_SELECTED = 32; + Selection selection[MAX_SELECTED]; + void HitTestMakeSelection(Point2d mp, Selection *dest); + // This sets what gets displayed. bool show2dCsyss; bool showAxes; diff --git a/util.cpp b/util.cpp index 6b3a6c9..2138e5e 100644 --- a/util.cpp +++ b/util.cpp @@ -160,4 +160,49 @@ Vector Vector::ScaledBy(double v) { return r; } +Point2d Point2d::Plus(Point2d b) { + Point2d r; + r.x = x + b.x; + r.y = y + b.y; + return r; +} + +Point2d Point2d::Minus(Point2d b) { + Point2d r; + r.x = x - b.x; + r.y = y - b.y; + return r; +} + +Point2d Point2d::ScaledBy(double s) { + Point2d r; + r.x = x*s; + r.y = y*s; + return r; +} + +double Point2d::DistanceTo(Point2d p) { + double dx = x - p.x; + double dy = y - p.y; + return sqrt(dx*dx + dy*dy); +} + +double Point2d::DistanceToLine(Point2d p0, Point2d dp, bool segment) { + double m = dp.x*dp.x + dp.y*dp.y; + if(m < 0.05) return 1e12; + + // Let our line be p = p0 + t*dp, for a scalar t from 0 to 1 + double t = (dp.x*(x - p0.x) + dp.y*(y - p0.y))/m; + + if((t < 0 || t > 1) && segment) { + // The closest point is one of the endpoints; determine which. + double d0 = DistanceTo(p0); + double d1 = DistanceTo(p0.Plus(dp)); + + return min(d1, d0); + } else { + Point2d closest = p0.Plus(dp.ScaledBy(t)); + return DistanceTo(closest); + } +} diff --git a/win32/w32main.cpp b/win32/w32main.cpp index 3f3d3c8..4487ea8 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -58,11 +58,9 @@ static void PaintTextWnd(HDC hdc) 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; TextWndScrollPos = min(TextWndScrollPos, SS.TW.rows - rows); @@ -101,21 +99,10 @@ static void PaintTextWnd(HDC hdc) } } - SetTextColor(backDc, SS.TW.COLOR_FG_CMDLINE); - SetBkColor(backDc, SS.TW.COLOR_BG_CMDLINE); - TextOut(backDc, 4, rows*TEXT_HEIGHT+1, 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); } @@ -232,18 +219,13 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; } - case WM_CHAR: - SS.TW.KeyPressed(wParam); - InvalidateRect(TextWnd, NULL, FALSE); - break; - 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, - (r.bottom - r.top) - TEXT_HEIGHT, TRUE); + (r.bottom - r.top), TRUE); InvalidateRect(TextWnd, NULL, FALSE); break; } @@ -300,12 +282,6 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { - case WM_CHAR: - SS.TW.KeyPressed(wParam); - SetForegroundWindow(TextWnd); - InvalidateRect(TextWnd, NULL, FALSE); - break; - case WM_ERASEBKGND: break; @@ -433,7 +409,8 @@ static void CreateMainWindows(void) if(!RegisterClassEx(&wc)) oops(); HMENU top = CreateGraphicsWindowMenus(); - GraphicsWnd = CreateWindowEx(0, "GraphicsWnd", "SolveSpace (View Sketch)", + GraphicsWnd = CreateWindowEx(0, "GraphicsWnd", + "SolveSpace (Graphics Window)", WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_CLIPSIBLINGS, 600, 300, 200, 200, NULL, top, Instance, NULL); @@ -452,7 +429,7 @@ static void CreateMainWindows(void) // 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)", + "TextWnd", "SolveSpace (Text Window)", WS_THICKFRAME | WS_CLIPCHILDREN, 10, 10, 600, 300, GraphicsWnd, (HMENU)NULL, Instance, NULL); if(!TextWnd) oops();