From 749e2a01491b052675fdb67c7eb35364b4b84cc5 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Sat, 17 May 2008 00:02:39 -0800 Subject: [PATCH] Add double-sided extrudes, and user interface for that. Also put the coordinate system (x, y, z normal vectors) in the bottom left corner of the screen at all times, and hide group-created workplanes except when that group is active, and activate that workplane when the group is activated. [git-p4: depot-paths = "//depot/solvespace/": change = 1726] --- constraint.cpp | 2 +- entity.cpp | 76 ++++++++++++++++++++++++++------------- file.cpp | 2 +- graphicswin.cpp | 21 +++++++---- sketch.cpp | 92 +++++++++++++++++++++++++++++------------------ sketch.h | 8 +++-- textwin.cpp | 58 +++++++++++++++++++++++------- ui.h | 4 +++ win32/w32main.cpp | 2 ++ 9 files changed, 182 insertions(+), 83 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index 9556a9e..db59e67 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -9,7 +9,7 @@ char *Constraint::DescriptionString(void) { hConstraint Constraint::AddConstraint(Constraint *c) { SS.constraint.AddAndAssignId(c); - SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); return c->h; } diff --git a/entity.cpp b/entity.cpp index b713dbb..c65d65f 100644 --- a/entity.cpp +++ b/entity.cpp @@ -332,7 +332,7 @@ void Entity::PointForceTo(Vector p) { } case POINT_N_TRANS: { - Vector trans = p.Minus(numPoint); + Vector trans = (p.Minus(numPoint)).ScaledBy(1.0/timesApplied); SS.GetParam(param[0])->val = trans.x; SS.GetParam(param[1])->val = trans.y; SS.GetParam(param[2])->val = trans.z; @@ -379,9 +379,9 @@ Vector Entity::PointGetNum(void) { case POINT_N_TRANS: { p = numPoint; - p.x += SS.GetParam(param[0])->val; - p.y += SS.GetParam(param[1])->val; - p.z += SS.GetParam(param[2])->val; + p.x += timesApplied * SS.GetParam(param[0])->val; + p.y += timesApplied * SS.GetParam(param[1])->val; + p.z += timesApplied * SS.GetParam(param[2])->val; break; } @@ -432,7 +432,7 @@ ExprVector Entity::PointGetExprs(void) { trans.x = Expr::FromParam(param[0]); trans.y = Expr::FromParam(param[1]); trans.z = Expr::FromParam(param[2]); - r = orig.Plus(trans); + r = orig.Plus(trans.ScaledBy(Expr::FromConstant(timesApplied))); break; } case POINT_N_ROT_TRANS: { @@ -619,27 +619,47 @@ void Entity::DrawOrGetDistance(int order) { if(order >= 0 && order != 2) break; if(!SS.GW.showNormals) break; - hRequest hr = h.request(); - double f = 0.5; - if(hr.v == Request::HREQUEST_REFERENCE_XY.v) { - glxColor3d(0, 0, f); - } else if(hr.v == Request::HREQUEST_REFERENCE_YZ.v) { - glxColor3d(f, 0, 0); - } else if(hr.v == Request::HREQUEST_REFERENCE_ZX.v) { - glxColor3d(0, f, 0); - } else { - glxColor3d(0, 0.4, 0.4); - } - Quaternion q = NormalGetNum(); - Vector tail = SS.GetEntity(point[0])->PointGetNum(); - Vector v = (q.RotationN()).WithMagnitude(50/SS.GW.scale); - Vector tip = tail.Plus(v); - LineDrawOrGetDistance(tail, tip); + int i; + for(i = 0; i < 2; i++) { + hRequest hr = h.request(); + double f = (i == 0 ? 0.4 : 1); + if(hr.v == Request::HREQUEST_REFERENCE_XY.v) { + glxColor3d(0, 0, f); + } else if(hr.v == Request::HREQUEST_REFERENCE_YZ.v) { + glxColor3d(f, 0, 0); + } else if(hr.v == Request::HREQUEST_REFERENCE_ZX.v) { + glxColor3d(0, f, 0); + } else { + glxColor3d(0, 0.4, 0.4); + if(i > 0) break; + } - v = v.WithMagnitude(12/SS.GW.scale); - Vector axis = q.RotationV(); - LineDrawOrGetDistance(tip, tip.Minus(v.RotatedAbout(axis, 0.6))); - LineDrawOrGetDistance(tip, tip.Minus(v.RotatedAbout(axis, -0.6))); + Quaternion q = NormalGetNum(); + Vector tail; + if(i == 0) { + tail = SS.GetEntity(point[0])->PointGetNum(); + } else { + // Draw an extra copy of the x, y, and z axes, that's + // always in the corner of the view and at the front. + // So those are always available, perhaps useful. + double s = SS.GW.scale; + double h = 60 - SS.GW.height/2; + double w = 60 - SS.GW.width/2; + Vector gn = SS.GW.projRight.Cross(SS.GW.projUp); + tail = SS.GW.projRight.ScaledBy(w/s).Plus( + SS.GW.projUp. ScaledBy(h/s)).Plus( + gn.ScaledBy(-4*w/s)).Minus(SS.GW.offset); + } + + Vector v = (q.RotationN()).WithMagnitude(50/SS.GW.scale); + Vector tip = tail.Plus(v); + LineDrawOrGetDistance(tail, tip); + + v = v.WithMagnitude(12/SS.GW.scale); + Vector axis = q.RotationV(); + LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis, 0.6))); + LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis,-0.6))); + } break; } @@ -652,6 +672,12 @@ void Entity::DrawOrGetDistance(int order) { if(order >= 0 && order != 0) break; if(!SS.GW.showWorkplanes) break; + if((!h.isFromRequest()) && (h.group().v != SS.GW.activeGroup.v)) { + // Workplanes that are automatically created by an in-wrkpl + // drawing group appear only when that group is active. + break; + } + Vector p; p = SS.GetEntity(point[0])->PointGetNum(); diff --git a/file.cpp b/file.cpp index 6015020..76cfb11 100644 --- a/file.cpp +++ b/file.cpp @@ -50,7 +50,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = { { 'g', "Group.name", 'N', &(SS.sv.g.name) }, { 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) }, { 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) }, - { 'g', "Group.wrkpl.type", 'd', &(SS.sv.g.wrkpl.type) }, + { 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) }, { 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) }, { 'g', "Group.wrkpl.q.vx", 'f', &(SS.sv.g.wrkpl.q.vx) }, { 'g', "Group.wrkpl.q.vy", 'f', &(SS.sv.g.wrkpl.q.vy) }, diff --git a/graphicswin.cpp b/graphicswin.cpp index 59ee12d..ac45072 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -267,6 +267,10 @@ void GraphicsWindow::EnsureValidActives(void) { if(change) SS.TW.Show(); } +void GraphicsWindow::GeneratePerSolving(void) { + SS.GenerateAll(solving == SOLVE_ALWAYS); +} + void GraphicsWindow::MenuEdit(int id) { switch(id) { case MNU_UNSELECT_ALL: @@ -302,7 +306,7 @@ void GraphicsWindow::MenuEdit(int id) { SS.GW.hover.Clear(); // And regenerate to get rid of what it generates, plus anything // that references it (since the regen code checks for that). - SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); SS.GW.EnsureValidActives(); SS.TW.Show(); break; @@ -365,7 +369,7 @@ c: r->construction = !(r->construction); } SS.GW.ClearSelection(); - SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); break; } @@ -607,7 +611,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, default: oops(); } - SS.GenerateAll(solving == SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); havePainted = false; } @@ -958,7 +962,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { break; } } - SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); SS.TW.Show(); InvalidateGraphics(); @@ -998,7 +1002,7 @@ void GraphicsWindow::EditControlDone(char *s) { Expr::FreeKeep(&(c->exprA)); c->exprA = e->DeepCopyKeep(); HideGraphicsEditControl(); - SS.GenerateAll(solving == SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); } else { Error("Not a valid number or expression: '%s'", s); } @@ -1030,7 +1034,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) { bool *vb = (bool *)v; *vb = !*vb; - SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); InvalidateGraphics(); SS.TW.Show(); } @@ -1041,7 +1045,7 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) { SS.GW.showNormals = t; SS.GW.showPoints = t; - SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS); + SS.GW.GeneratePerSolving(); InvalidateGraphics(); SS.TW.Show(); } @@ -1090,6 +1094,9 @@ void GraphicsWindow::Paint(int w, int h) { glEnable(GL_DEPTH_TEST); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_NORMALIZE); + + // At the same depth, we want later lines drawn over earlier. + glDepthFunc(GL_LEQUAL); glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/sketch.cpp b/sketch.cpp index d430c21..519d902 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -37,7 +37,7 @@ void Group::MenuGroup(int id) { g.type = DRAWING_WORKPLANE; g.name.strcpy("draw-in-plane"); if(gs.points == 1 && gs.n == 1) { - g.wrkpl.type = WORKPLANE_BY_POINT_ORTHO; + g.subtype = WORKPLANE_BY_POINT_ORTHO; Vector u = SS.GW.projRight, v = SS.GW.projUp; u = u.ClosestOrtho(); @@ -47,7 +47,7 @@ void Group::MenuGroup(int id) { g.wrkpl.q = Quaternion::MakeFrom(u, v); g.wrkpl.origin = gs.point[0]; } else if(gs.points == 1 && gs.lineSegments == 2 && gs.n == 3) { - g.wrkpl.type = WORKPLANE_BY_LINE_SEGMENTS; + g.subtype = WORKPLANE_BY_LINE_SEGMENTS; g.wrkpl.origin = gs.point[0]; g.wrkpl.entityB = gs.entity[0]; @@ -75,6 +75,7 @@ void Group::MenuGroup(int id) { g.type = EXTRUDE; g.opA = SS.GW.activeGroup; g.wrkpl.entityB = SS.GW.activeWorkplane; + g.subtype = EXTRUDE_TWO_SIDED; g.name.strcpy("extrude"); break; @@ -122,7 +123,7 @@ void Group::Generate(IdList *entity, case DRAWING_WORKPLANE: { Quaternion q; - if(wrkpl.type == WORKPLANE_BY_LINE_SEGMENTS) { + if(subtype == WORKPLANE_BY_LINE_SEGMENTS) { Vector u = SS.GetEntity(wrkpl.entityB)->VectorGetNum(); Vector v = SS.GetEntity(wrkpl.entityC)->VectorGetNum(); u = u.WithMagnitude(1); @@ -133,7 +134,7 @@ void Group::Generate(IdList *entity, if(wrkpl.negateU) u = u.ScaledBy(-1); if(wrkpl.negateV) v = v.ScaledBy(-1); q = Quaternion::MakeFrom(u, v); - } else if(wrkpl.type == WORKPLANE_BY_POINT_ORTHO) { + } else if(subtype == WORKPLANE_BY_POINT_ORTHO) { // Already given, numerically. q = wrkpl.q; } else oops(); @@ -170,14 +171,28 @@ void Group::Generate(IdList *entity, AddParam(param, h.param(0), gn.x); AddParam(param, h.param(1), gn.y); AddParam(param, h.param(2), gn.z); + int ai, af; + if(subtype == EXTRUDE_ONE_SIDED) { + ai = 0; af = 1; + } else if(subtype == EXTRUDE_TWO_SIDED) { + ai = -1; af = 1; + } else oops(); for(i = 0; i < entity->n; i++) { Entity *e = &(entity->elem[i]); if(e->group.v != opA.v) continue; - CopyEntity(e->h, 0, + hEntity he = e->h; e = NULL; + // As soon as I call CopyEntity, e may become invalid! That + // adds entities, which may cause a realloc. + CopyEntity(he, ai, h.param(0), h.param(1), h.param(2), NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, - true, true); + true); + CopyEntity(he, af, + h.param(0), h.param(1), h.param(2), + NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM, + true); + MakeExtrusionLines(he, ai, af); } break; @@ -199,7 +214,7 @@ void Group::Generate(IdList *entity, CopyEntity(e->h, 0, h.param(0), h.param(1), h.param(2), h.param(3), h.param(4), h.param(5), h.param(6), - false, false); + false); } break; @@ -255,9 +270,24 @@ hEntity Group::Remap(hEntity in, int copyNumber) { return h.entity(em.h.v); } +void Group::MakeExtrusionLines(hEntity in, int ai, int af) { + Entity *ep = SS.GetEntity(in); + if(!(ep->IsPoint())) return; + + Entity en; + memset(&en, 0, sizeof(en)); + en.point[0] = Remap(ep->h, ai); + en.point[1] = Remap(ep->h, af); + en.group = h; + en.h = Remap(ep->h, 10); + en.type = Entity::LINE_SEGMENT; + // And then this line segment gets added + SS.entity.Add(&en); +} + void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, - bool transOnly, bool isExtrusion) + bool transOnly) { Entity *ep = SS.GetEntity(in); @@ -307,7 +337,6 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz, en.param[0] = dx; en.param[1] = dy; en.param[2] = dz; - en.numPoint = ep->PointGetNum(); } else { en.type = Entity::POINT_N_ROT_TRANS; en.param[0] = dx; @@ -317,25 +346,9 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz, en.param[4] = qvx; en.param[5] = qvy; en.param[6] = qvz; - en.numPoint = ep->PointGetNum(); - } - - if(isExtrusion) { - if(a != 0) oops(); - SS.entity.Add(&en); - - // Any operation on these lists may break existing pointers! - ep = SS.GetEntity(in); - - hEntity np = en.h; - memset(&en, 0, sizeof(en)); - en.point[0] = ep->h; - en.point[1] = np; - en.group = h; - en.h = Remap(ep->h, 1); - en.type = Entity::LINE_SEGMENT; - // And then this line segment gets added } + en.numPoint = ep->PointGetNum(); + en.timesApplied = a; break; case Entity::NORMAL_N_COPY: @@ -344,16 +357,16 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz, case Entity::NORMAL_IN_2D: if(transOnly) { en.type = Entity::NORMAL_N_COPY; - en.numNormal = ep->NormalGetNum(); } else { en.type = Entity::NORMAL_N_ROT; - en.numNormal = ep->NormalGetNum(); en.param[0] = qw; en.param[1] = qvx; en.param[2] = qvy; en.param[3] = qvz; } + en.numNormal = ep->NormalGetNum(); en.point[0] = Remap(ep->point[0], a); + en.timesApplied = a; break; case Entity::DISTANCE_N_COPY: @@ -400,12 +413,24 @@ void Group::MakePolygons(void) { translate.x = SS.GetParam(h.param(0))->val; translate.y = SS.GetParam(h.param(1))->val; translate.z = SS.GetParam(h.param(2))->val; + Vector t0, dt; + if(subtype == EXTRUDE_ONE_SIDED) { + t0 = Vector::MakeFrom(0, 0, 0); dt = translate; + } else { + t0 = translate.ScaledBy(-1); dt = translate.ScaledBy(2); + } + // Get the source polygon to extrude, and break it down to edges edges.l.Clear(); Group *src = SS.GetGroup(opA); if(src->faces.n != 1) return; (src->faces.elem[0]).MakeEdgesInto(&edges); + for(i = 0; i < edges.l.n; i++) { + SEdge *edge = &(edges.l.elem[i]); + edge->a = (edge->a).Plus(t0); + edge->b = (edge->b).Plus(t0); + } SPolygon poly; SEdge error; @@ -419,7 +444,6 @@ void Group::MakePolygons(void) { } poly.normal = n; poly.FixContourDirections(); - poly.FixContourDirections(); faces.Add(&poly); // Regenerate the edges, with the contour directions fixed up. @@ -434,14 +458,14 @@ void Group::MakePolygons(void) { poly.AddEmptyContour(); poly.AddPoint(edge->a); poly.AddPoint(edge->b); - poly.AddPoint((edge->b).Plus(translate)); - poly.AddPoint((edge->a).Plus(translate)); + poly.AddPoint((edge->b).Plus(dt)); + poly.AddPoint((edge->a).Plus(dt)); poly.AddPoint(edge->a); poly.normal = ((edge->a).Minus(edge->b).Cross(n)).WithMagnitude(1); faces.Add(&poly); - edge->a = (edge->a).Plus(translate); - edge->b = (edge->b).Plus(translate); + edge->a = (edge->a).Plus(dt); + edge->b = (edge->b).Plus(dt); } // The top diff --git a/sketch.h b/sketch.h index 92b08d2..04be53f 100644 --- a/sketch.h +++ b/sketch.h @@ -92,8 +92,11 @@ public: static const int WORKPLANE_BY_POINT_ORTHO = 6000; static const int WORKPLANE_BY_LINE_SEGMENTS = 6001; + static const int EXTRUDE_ONE_SIDED = 7000; + static const int EXTRUDE_TWO_SIDED = 7001; + int subtype; + struct { - int type; Quaternion q; hEntity origin; hEntity entityB; @@ -121,9 +124,10 @@ public: // mapping list. IdList remap; hEntity Remap(hEntity in, int copyNumber); + void MakeExtrusionLines(hEntity in, int ai, int af); void CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, - bool transOnly, bool isExtrusion); + bool transOnly); void GenerateEquations(IdList *l); diff --git a/textwin.cpp b/textwin.cpp index e7efcd6..b53c08d 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -210,7 +210,6 @@ void TextWindow::ScreenNavigation(int link, DWORD v) { SS.TW.OneScreenForwardTo(-1); break; } - SS.TW.Show(); } void TextWindow::ShowHeader(void) { ClearScreen(); @@ -262,25 +261,37 @@ hs(SS.GW.showHdnLines), (DWORD)(&SS.GW.showHdnLines), &(SS.GW.ToggleBool) void TextWindow::ScreenSelectGroup(int link, DWORD v) { SS.TW.OneScreenForwardTo(SCREEN_GROUP_INFO); SS.TW.shown->group.v = v; - - SS.TW.Show(); } void TextWindow::ScreenToggleGroupShown(int link, DWORD v) { hGroup hg = { v }; Group *g = SS.GetGroup(hg); g->visible = !(g->visible); +} +void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) { + int i; + bool before = true; + for(i = 0; i < SS.group.n; i++) { + Group *g = &(SS.group.elem[i]); - InvalidateGraphics(); - SS.TW.Show(); + if(g->h.v == SS.GW.activeGroup.v) { + before = false; + } else if(before && link == 's') { + g->visible = true; + } else if(!before && link == 'h') { + g->visible = false; + } + } } void TextWindow::ScreenActivateGroup(int link, DWORD v) { hGroup hg = { v }; Group *g = SS.GetGroup(hg); g->visible = true; SS.GW.activeGroup.v = v; - - InvalidateGraphics(); - SS.TW.Show(); + if(g->type == Group::DRAWING_WORKPLANE) { + // If we're activating an in-workplane drawing, then activate that + // workplane too. + SS.GW.activeWorkplane = g->h.entity(0); + } } void TextWindow::ShowListOfGroups(void) { Printf(true, "%Ftactive show group-name%E"); @@ -309,20 +320,30 @@ void TextWindow::ShowListOfGroups(void) { // Link to a screen that gives more details on the group g->h.v, (&TextWindow::ScreenSelectGroup), s); } + + Printf(true, " %Fl%Ls%fshow all groups before active%E", + &(TextWindow::ScreenShowGroupsSpecial)); + Printf(false, " %Fl%Lh%fhide all groups after active%E", + &(TextWindow::ScreenShowGroupsSpecial)); } void TextWindow::ScreenSelectConstraint(int link, DWORD v) { SS.TW.OneScreenForwardTo(SCREEN_CONSTRAINT_INFO); SS.TW.shown->constraint.v = v; - - SS.TW.Show(); } void TextWindow::ScreenSelectRequest(int link, DWORD v) { SS.TW.OneScreenForwardTo(SCREEN_REQUEST_INFO); SS.TW.shown->request.v = v; - - SS.TW.Show(); +} +void TextWindow::ScreenChangeExtrudeSides(int link, DWORD v) { + Group *g = SS.GetGroup(SS.TW.shown->group); + if(g->subtype == Group::EXTRUDE_ONE_SIDED) { + g->subtype = Group::EXTRUDE_TWO_SIDED; + } else { + g->subtype = Group::EXTRUDE_ONE_SIDED; + } + SS.GW.GeneratePerSolving(); } void TextWindow::ShowGroupInfo(void) { Group *g = SS.group.FindById(shown->group); @@ -334,7 +355,18 @@ void TextWindow::ShowGroupInfo(void) { } else { s = ""; } - Printf(true, "%Ft%sgroup %E%s", s, g->DescriptionString()); + Printf(true, "%Ft%sGROUP %E%s", s, g->DescriptionString()); + + if(g->type == Group::EXTRUDE) { + bool one = (g->subtype == Group::EXTRUDE_ONE_SIDED); + Printf(true, "%FtEXTRUDE%E one-sided: %Fh%f%Ll%s%E%Fs%s%E", + &TextWindow::ScreenChangeExtrudeSides, + (one ? "" : "no"), (one ? "yes" : "")); + Printf(false, " two-sided: %Fh%f%Ll%s%E%Fs%s%E", + &TextWindow::ScreenChangeExtrudeSides, + (!one ? "" : "no"), (!one ? "yes" : "")); + } + Printf(true, "%Ftrequests in group"); int i, a = 0; diff --git a/ui.h b/ui.h index f4920d1..32fc167 100644 --- a/ui.h +++ b/ui.h @@ -69,9 +69,12 @@ public: static void ScreenSelectGroup(int link, DWORD v); static void ScreenActivateGroup(int link, DWORD v); static void ScreenToggleGroupShown(int link, DWORD v); + static void ScreenShowGroupsSpecial(int link, DWORD v); static void ScreenSelectRequest(int link, DWORD v); static void ScreenSelectConstraint(int link, DWORD v); + static void ScreenChangeExtrudeSides(int link, DWORD v); + static void ScreenNavigation(int link, DWORD v); }; @@ -254,6 +257,7 @@ public: static const int DONT_SOLVE = 0; static const int SOLVE_ALWAYS = 1; int solving; + void GeneratePerSolving(void); void UpdateDraggedNum(Vector *pos, double mx, double my); void UpdateDraggedPoint(hEntity hp, double mx, double my); diff --git a/win32/w32main.cpp b/win32/w32main.cpp index 3cda5e0..a48cee2 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -318,6 +318,8 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) SS.TW.meta[r][c].link, SS.TW.meta[r][c].data ); + SS.TW.Show(); + InvalidateGraphics(); } } break;