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