diff --git a/CHANGELOG.md b/CHANGELOG.md index 8447d0ef..f70812ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ New sketch features: * Property browser now shows amount of degrees of freedom in group list. It also shows a yellow "err" if the sketch has problems (e.g. self intersecting) that would propagate in subsequent groups. + * It is now possible to press "g" to toggle construction on new objects while + they are still being drawn. New constraint features: * When dragging an arc or rectangle point, it will be automatically @@ -47,6 +49,10 @@ New constraint features: would have been redundant with other ones. * New option to open the constraint editor for newly created constraints with a value. + * New "redundant constraint timeout (in ms)" option to prevent UI freeze + when looking for redundant constraints. + * Swap vertical and horizontal constraints when pasting rotated by 90/270 + degrees. New export/import features: * Link IDF circuit boards in an assembly (.emn files) @@ -63,12 +69,17 @@ New export/import features: * VRML (WRL) triangle meshes can now be exported, useful for e.g. [KiCAD](http://kicad.org). * Export 2d section: custom styled entities that lie in the same plane as the exported section are included. + * Added ExportBackgroundColor in configuration for EPS, PDF, and SVG files. + * STEP export includes object colors and transparency. New rendering features: * The "Show/hide hidden lines" button is now a tri-state button that allows showing all lines (on top of shaded mesh), stippling occluded lines or not drawing them at all. * The "Show/hide outlines" button is now independent from "Show/hide edges". + * "View | Darken Inactive Solids" added. When turned off and a "sketch in plane" + group is active solids form previous groups will not be "darkened" (have the + s000d-#def-dim-solid style applied to them). New measurement/analysis features: * New choice for base unit, meters. @@ -85,7 +96,6 @@ New measurement/analysis features: workplane is displayed. Other new features: - * Added ExportBackgroundColor in configuration for EPS, PDF, and SVG files. * Improvements to the text window for selected entities and constraints. * Ambient light source added in text window to allow flat shaded renderings. * New command-line interface, for batch exporting and more. @@ -114,6 +124,7 @@ Other new features: * New cmake build options using -DENABLE_OPENMP=yes and -DENABLE_LTO=yes to enable support for multi-threading and link-time optimization. * "Shift+Scroll" for ten times finer zoom. + * Chinese translation Bugs fixed: * Fixed broken --view options for command line thumbnail image creation. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aee8bb59..5636b39b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,8 +17,8 @@ so any savefiles should first be archived. Licensing --------------- -SolveSpace is licensed under the GPLv3 and any contributions must be made available -under the terms of that license. +SolveSpace is licensed under the GPLv3 or later and any contributions +must be made available under the terms of that license. Contributing translations ------------------------- diff --git a/README.md b/README.md index a5bb470e..9b6cb225 100644 --- a/README.md +++ b/README.md @@ -259,4 +259,4 @@ and debug SolveSpace. License ------- -SolveSpace is distributed under the terms of the [GPL v3 license](COPYING.txt). +SolveSpace is distributed under the terms of the [GPL v3](COPYING.txt) or later. diff --git a/res/fonts/unicode.lff.gz b/res/fonts/unicode.lff.gz index ec0501dd..6b1b04da 100644 Binary files a/res/fonts/unicode.lff.gz and b/res/fonts/unicode.lff.gz differ diff --git a/res/icons/graphics-window/angle.png b/res/icons/graphics-window/angle.png index f70252a9..8b82ba3d 100644 Binary files a/res/icons/graphics-window/angle.png and b/res/icons/graphics-window/angle.png differ diff --git a/res/icons/graphics-window/arc.png b/res/icons/graphics-window/arc.png index 807b7366..0acded45 100644 Binary files a/res/icons/graphics-window/arc.png and b/res/icons/graphics-window/arc.png differ diff --git a/res/icons/graphics-window/assemble.png b/res/icons/graphics-window/assemble.png index 4dad1f72..8436dcdd 100644 Binary files a/res/icons/graphics-window/assemble.png and b/res/icons/graphics-window/assemble.png differ diff --git a/res/icons/graphics-window/bezier.png b/res/icons/graphics-window/bezier.png index 9d2c240a..fd7d438a 100644 Binary files a/res/icons/graphics-window/bezier.png and b/res/icons/graphics-window/bezier.png differ diff --git a/res/icons/graphics-window/circle.png b/res/icons/graphics-window/circle.png index c176b440..6ec2c83f 100644 Binary files a/res/icons/graphics-window/circle.png and b/res/icons/graphics-window/circle.png differ diff --git a/res/icons/graphics-window/construction.png b/res/icons/graphics-window/construction.png index 35ddcb27..6f48aede 100644 Binary files a/res/icons/graphics-window/construction.png and b/res/icons/graphics-window/construction.png differ diff --git a/res/icons/graphics-window/equal.png b/res/icons/graphics-window/equal.png index 6037aed0..ba9053aa 100644 Binary files a/res/icons/graphics-window/equal.png and b/res/icons/graphics-window/equal.png differ diff --git a/res/icons/graphics-window/extrude.png b/res/icons/graphics-window/extrude.png index 5b57a0eb..ad71bce3 100644 Binary files a/res/icons/graphics-window/extrude.png and b/res/icons/graphics-window/extrude.png differ diff --git a/res/icons/graphics-window/helix.png b/res/icons/graphics-window/helix.png index 4b2cda68..ac4f5096 100644 Binary files a/res/icons/graphics-window/helix.png and b/res/icons/graphics-window/helix.png differ diff --git a/res/icons/graphics-window/horiz.png b/res/icons/graphics-window/horiz.png index dc94540a..3c23d677 100644 Binary files a/res/icons/graphics-window/horiz.png and b/res/icons/graphics-window/horiz.png differ diff --git a/res/icons/graphics-window/image.png b/res/icons/graphics-window/image.png index d652d8e7..5df953a7 100644 Binary files a/res/icons/graphics-window/image.png and b/res/icons/graphics-window/image.png differ diff --git a/res/icons/graphics-window/in3d.png b/res/icons/graphics-window/in3d.png index bad460f0..bf395f62 100644 Binary files a/res/icons/graphics-window/in3d.png and b/res/icons/graphics-window/in3d.png differ diff --git a/res/icons/graphics-window/lathe.png b/res/icons/graphics-window/lathe.png index 8cee0583..02625401 100644 Binary files a/res/icons/graphics-window/lathe.png and b/res/icons/graphics-window/lathe.png differ diff --git a/res/icons/graphics-window/length.png b/res/icons/graphics-window/length.png index b48715e0..552c87c6 100644 Binary files a/res/icons/graphics-window/length.png and b/res/icons/graphics-window/length.png differ diff --git a/res/icons/graphics-window/line.png b/res/icons/graphics-window/line.png index b99a0d86..356130f9 100644 Binary files a/res/icons/graphics-window/line.png and b/res/icons/graphics-window/line.png differ diff --git a/res/icons/graphics-window/ontoworkplane.png b/res/icons/graphics-window/ontoworkplane.png index fbf6ff30..66642a33 100644 Binary files a/res/icons/graphics-window/ontoworkplane.png and b/res/icons/graphics-window/ontoworkplane.png differ diff --git a/res/icons/graphics-window/other-supp.png b/res/icons/graphics-window/other-supp.png index b2ea5a95..a5577760 100644 Binary files a/res/icons/graphics-window/other-supp.png and b/res/icons/graphics-window/other-supp.png differ diff --git a/res/icons/graphics-window/parallel.png b/res/icons/graphics-window/parallel.png index fe89e2f1..5f76105d 100644 Binary files a/res/icons/graphics-window/parallel.png and b/res/icons/graphics-window/parallel.png differ diff --git a/res/icons/graphics-window/perpendicular.png b/res/icons/graphics-window/perpendicular.png index e9bf5d5f..21277143 100644 Binary files a/res/icons/graphics-window/perpendicular.png and b/res/icons/graphics-window/perpendicular.png differ diff --git a/res/icons/graphics-window/point.png b/res/icons/graphics-window/point.png index d50ffffb..a1a56660 100644 Binary files a/res/icons/graphics-window/point.png and b/res/icons/graphics-window/point.png differ diff --git a/res/icons/graphics-window/pointonx.png b/res/icons/graphics-window/pointonx.png index d0f6b674..0fa95065 100644 Binary files a/res/icons/graphics-window/pointonx.png and b/res/icons/graphics-window/pointonx.png differ diff --git a/res/icons/graphics-window/rectangle.png b/res/icons/graphics-window/rectangle.png index d36dc4c5..3f9ea7cc 100644 Binary files a/res/icons/graphics-window/rectangle.png and b/res/icons/graphics-window/rectangle.png differ diff --git a/res/icons/graphics-window/ref.png b/res/icons/graphics-window/ref.png index 19f3b88a..6bc2894f 100644 Binary files a/res/icons/graphics-window/ref.png and b/res/icons/graphics-window/ref.png differ diff --git a/res/icons/graphics-window/revolve.png b/res/icons/graphics-window/revolve.png index 0cef0fa6..110a0123 100644 Binary files a/res/icons/graphics-window/revolve.png and b/res/icons/graphics-window/revolve.png differ diff --git a/res/icons/graphics-window/same-orientation.png b/res/icons/graphics-window/same-orientation.png index 850d2da8..7223d0cc 100644 Binary files a/res/icons/graphics-window/same-orientation.png and b/res/icons/graphics-window/same-orientation.png differ diff --git a/res/icons/graphics-window/sketch-in-3d.png b/res/icons/graphics-window/sketch-in-3d.png index 0a73b6b5..d15a0d32 100644 Binary files a/res/icons/graphics-window/sketch-in-3d.png and b/res/icons/graphics-window/sketch-in-3d.png differ diff --git a/res/icons/graphics-window/sketch-in-plane.png b/res/icons/graphics-window/sketch-in-plane.png index c52c40cf..30c99beb 100644 Binary files a/res/icons/graphics-window/sketch-in-plane.png and b/res/icons/graphics-window/sketch-in-plane.png differ diff --git a/res/icons/graphics-window/step-rotate.png b/res/icons/graphics-window/step-rotate.png index 22969f65..a64eae44 100644 Binary files a/res/icons/graphics-window/step-rotate.png and b/res/icons/graphics-window/step-rotate.png differ diff --git a/res/icons/graphics-window/step-translate.png b/res/icons/graphics-window/step-translate.png index 2901f9e5..493f8533 100644 Binary files a/res/icons/graphics-window/step-translate.png and b/res/icons/graphics-window/step-translate.png differ diff --git a/res/icons/graphics-window/symmetric.png b/res/icons/graphics-window/symmetric.png index e6e80ebe..41926842 100644 Binary files a/res/icons/graphics-window/symmetric.png and b/res/icons/graphics-window/symmetric.png differ diff --git a/res/icons/graphics-window/tangent-arc.png b/res/icons/graphics-window/tangent-arc.png index d9dc40ac..88feddbd 100644 Binary files a/res/icons/graphics-window/tangent-arc.png and b/res/icons/graphics-window/tangent-arc.png differ diff --git a/res/icons/graphics-window/text.png b/res/icons/graphics-window/text.png index 8923573a..886a80aa 100644 Binary files a/res/icons/graphics-window/text.png and b/res/icons/graphics-window/text.png differ diff --git a/res/icons/graphics-window/trim.png b/res/icons/graphics-window/trim.png index 248e448c..de11e17a 100644 Binary files a/res/icons/graphics-window/trim.png and b/res/icons/graphics-window/trim.png differ diff --git a/res/icons/graphics-window/vert.png b/res/icons/graphics-window/vert.png index f137913c..996b191e 100644 Binary files a/res/icons/graphics-window/vert.png and b/res/icons/graphics-window/vert.png differ diff --git a/res/icons/text-window/constraint.png b/res/icons/text-window/constraint.png index bc1a7178..431ed754 100644 Binary files a/res/icons/text-window/constraint.png and b/res/icons/text-window/constraint.png differ diff --git a/res/icons/text-window/construction.png b/res/icons/text-window/construction.png index 35ddcb27..0ecc9a13 100644 Binary files a/res/icons/text-window/construction.png and b/res/icons/text-window/construction.png differ diff --git a/res/icons/text-window/edges.png b/res/icons/text-window/edges.png index fcfd009f..f428de17 100644 Binary files a/res/icons/text-window/edges.png and b/res/icons/text-window/edges.png differ diff --git a/res/icons/text-window/faces.png b/res/icons/text-window/faces.png index e92cd5dc..57345dff 100644 Binary files a/res/icons/text-window/faces.png and b/res/icons/text-window/faces.png differ diff --git a/res/icons/text-window/mesh.png b/res/icons/text-window/mesh.png index efc6278a..260b083f 100644 Binary files a/res/icons/text-window/mesh.png and b/res/icons/text-window/mesh.png differ diff --git a/res/icons/text-window/normal.png b/res/icons/text-window/normal.png index c87ea517..95a83391 100644 Binary files a/res/icons/text-window/normal.png and b/res/icons/text-window/normal.png differ diff --git a/res/icons/text-window/occluded-invisible.png b/res/icons/text-window/occluded-invisible.png index 5ab4f82f..ed353012 100644 Binary files a/res/icons/text-window/occluded-invisible.png and b/res/icons/text-window/occluded-invisible.png differ diff --git a/res/icons/text-window/occluded-stippled.png b/res/icons/text-window/occluded-stippled.png index 6d7a33f2..04ee458e 100644 Binary files a/res/icons/text-window/occluded-stippled.png and b/res/icons/text-window/occluded-stippled.png differ diff --git a/res/icons/text-window/occluded-visible.png b/res/icons/text-window/occluded-visible.png index 2ccd73e6..23415c30 100644 Binary files a/res/icons/text-window/occluded-visible.png and b/res/icons/text-window/occluded-visible.png differ diff --git a/res/icons/text-window/outlines.png b/res/icons/text-window/outlines.png index 2c07fba0..f947ec7f 100644 Binary files a/res/icons/text-window/outlines.png and b/res/icons/text-window/outlines.png differ diff --git a/res/icons/text-window/point.png b/res/icons/text-window/point.png index 42168810..a1a56660 100644 Binary files a/res/icons/text-window/point.png and b/res/icons/text-window/point.png differ diff --git a/res/icons/text-window/workplane.png b/res/icons/text-window/workplane.png index 7df68975..8e293cd5 100644 Binary files a/res/icons/text-window/workplane.png and b/res/icons/text-window/workplane.png differ diff --git a/src/constraint.cpp b/src/constraint.cpp index 2acc2115..435fc3ac 100644 --- a/src/constraint.cpp +++ b/src/constraint.cpp @@ -127,7 +127,7 @@ hConstraint Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) { Entity::NO_ENTITY, Entity::NO_ENTITY, /*other=*/false, /*other2=*/false); } -void Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc) { +bool Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc) { Vector l0 = SK.GetEntity(line->point[0])->PointGetNum(), l1 = SK.GetEntity(line->point[1])->PointGetNum(); Vector a1 = SK.GetEntity(arc->point[1])->PointGetNum(), @@ -140,11 +140,12 @@ void Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *ar Error(_("The tangent arc and line segment must share an " "endpoint. Constrain them with Constrain -> " "On Point before constraining tangent.")); - return; + return false; } + return true; } -void Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic) { +bool Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic) { Vector l0 = SK.GetEntity(line->point[0])->PointGetNum(), l1 = SK.GetEntity(line->point[1])->PointGetNum(); Vector as = cubic->CubicGetStartNum(), @@ -158,11 +159,12 @@ void Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity * Error(_("The tangent cubic and line segment must share an " "endpoint. Constrain them with Constrain -> " "On Point before constraining tangent.")); - return; + return false; } + return true; } -void Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB) { +bool Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB) { Vector as = eA->EndpointStart(), af = eA->EndpointFinish(), bs = eB->EndpointStart(), @@ -183,8 +185,9 @@ void Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *e Error(_("The curves must share an endpoint. Constrain them " "with Constrain -> On Point before constraining " "tangent.")); - return; + return false; } + return true; } void Constraint::MenuConstrain(Command id) { @@ -417,8 +420,11 @@ void Constraint::MenuConstrain(Command id) { c.ptA = gs.point[0]; // If a point is at-midpoint, then no reason to also constrain - // it on-line; so auto-remove that. + // it on-line; so auto-remove that. Handle as one undo group. + SS.UndoRemember(); DeleteAllConstraintsFor(Type::PT_ON_LINE, c.entityA, c.ptA); + AddConstraint(&c, /*rememberForUndo=*/false); + break; } else if(gs.lineSegments == 1 && gs.workplanes == 1 && gs.n == 2) { c.type = Type::AT_MIDPOINT; int i = SK.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0; @@ -493,6 +499,7 @@ void Constraint::MenuConstrain(Command id) { "(symmetric about workplane)\n")); return; } + // We may remove constraints so remember manually if(c.entityA == Entity::NO_ENTITY) { // Horizontal / vertical symmetry, implicit symmetry plane // normal to the workplane @@ -514,10 +521,14 @@ void Constraint::MenuConstrain(Command id) { if(gs.lineSegments == 1) { // If this line segment is already constrained horiz or // vert, then auto-remove that redundant constraint. + // Handle as one undo group. + SS.UndoRemember(); DeleteAllConstraintsFor(Type::HORIZONTAL, (gs.entity[0]), Entity::NO_ENTITY); DeleteAllConstraintsFor(Type::VERTICAL, (gs.entity[0]), Entity::NO_ENTITY); + AddConstraint(&c, /*rememberForUndo=*/false); + break; } } AddConstraint(&c); @@ -682,7 +693,9 @@ void Constraint::MenuConstrain(Command id) { if(line->type == Entity::Type::ARC_OF_CIRCLE) { swap(line, arc); } - ConstrainArcLineTangent(&c, line, arc); + if(!ConstrainArcLineTangent(&c, line, arc)) { + return; + } c.type = Type::ARC_LINE_TANGENT; c.entityA = arc->h; c.entityB = line->h; @@ -692,7 +705,9 @@ void Constraint::MenuConstrain(Command id) { if(line->type == Entity::Type::CUBIC) { swap(line, cubic); } - ConstrainCubicLineTangent(&c, line, cubic); + if(!ConstrainCubicLineTangent(&c, line, cubic)) { + return; + } c.type = Type::CUBIC_LINE_TANGENT; c.entityA = cubic->h; c.entityB = line->h; @@ -703,7 +718,9 @@ void Constraint::MenuConstrain(Command id) { } Entity *eA = SK.GetEntity(gs.entity[0]), *eB = SK.GetEntity(gs.entity[1]); - ConstrainCurveCurveTangent(&c, eA, eB); + if(!ConstrainCurveCurveTangent(&c, eA, eB)) { + return; + } c.type = Type::CURVE_CURVE_TANGENT; c.entityA = eA->h; c.entityB = eB->h; diff --git a/src/describescreen.cpp b/src/describescreen.cpp index 03fafee1..2c36d988 100644 --- a/src/describescreen.cpp +++ b/src/describescreen.cpp @@ -318,8 +318,9 @@ void TextWindow::DescribeSelection() { Printf(true, " at " PT_AS_STR, COSTR(p0)); Vector p1 = SK.GetEntity(gs.point[1])->PointGetNum(); Printf(false, " " PT_AS_STR, COSTR(p1)); - double d = (p1.Minus(p0)).Magnitude(); - Printf(true, " d = %Fi%s", SS.MmToString(d).c_str()); + Vector dv = p1.Minus(p0); + Printf(true, " d = %Fi%s", SS.MmToString(dv.Magnitude()).c_str()); + Printf(false, " d(x, y, z) = " PT_AS_STR, COSTR(dv)); } else if(gs.n == 2 && gs.points == 1 && gs.circlesOrArcs == 1) { Entity *ec = SK.GetEntity(gs.entity[0]); if(ec->type == Entity::Type::CIRCLE) { diff --git a/src/drawentity.cpp b/src/drawentity.cpp index b8e3cbd5..00bcb28a 100644 --- a/src/drawentity.cpp +++ b/src/drawentity.cpp @@ -462,7 +462,7 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) const { // Record our style for all of the Beziers that we just created. for(; i < sbl->l.n; i++) { - sbl->l[i].auxA = style.v; + sbl->l[i].auxA = Style::ForEntity(h).v; } } diff --git a/src/export.cpp b/src/export.cpp index 970552c6..b9ebb914 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -207,7 +207,6 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const Platform::Path &filename, bool for(auto &entity : SK.entity) { Entity *e = &entity; if(!e->IsVisible()) continue; - if(e->construction) continue; if(SS.exportPwlCurves || sm || fabs(SS.exportOffset) > LENGTH_EPS) { @@ -735,25 +734,22 @@ void VectorFileWriter::OutputLinesAndMesh(SBezierLoopSetSet *sblss, SMesh *sm) { if(sblss) { SBezierLoopSet *sbls; for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) { - SBezierLoop *sbl; - sbl = sbls->l.First(); - if(!sbl) continue; - b = sbl->l.First(); - if(!b || !Style::Exportable(b->auxA)) continue; + for(SBezierLoop *sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) { + b = sbl->l.First(); + if(!b || !Style::Exportable(b->auxA)) continue; - hStyle hs = { (uint32_t)b->auxA }; - Style *stl = Style::Get(hs); - double lineWidth = Style::WidthMm(b->auxA)*s; - RgbaColor strokeRgb = Style::Color(hs, /*forExport=*/true); - RgbaColor fillRgb = Style::FillColor(hs, /*forExport=*/true); + hStyle hs = { (uint32_t)b->auxA }; + Style *stl = Style::Get(hs); + double lineWidth = Style::WidthMm(b->auxA)*s; + RgbaColor strokeRgb = Style::Color(hs, /*forExport=*/true); + RgbaColor fillRgb = Style::FillColor(hs, /*forExport=*/true); - StartPath(strokeRgb, lineWidth, stl->filled, fillRgb, hs); - for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) { + StartPath(strokeRgb, lineWidth, stl->filled, fillRgb, hs); for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) { Bezier(b); } + FinishPath(strokeRgb, lineWidth, stl->filled, fillRgb, hs); } - FinishPath(strokeRgb, lineWidth, stl->filled, fillRgb, hs); } } FinishAndCloseFile(); diff --git a/src/exportvector.cpp b/src/exportvector.cpp index 4a184abb..97730997 100644 --- a/src/exportvector.cpp +++ b/src/exportvector.cpp @@ -1083,17 +1083,18 @@ void SvgFileWriter::StartFile() { double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000; fprintf(f, "stroke-width:%f;\r\n", sw); fprintf(f, "}\r\n"); - for(auto &style : SK.style) { - Style *s = &style; - RgbaColor strokeRgb = Style::Color(s->h, /*forExport=*/true); - StipplePattern pattern = Style::PatternType(s->h); - double stippleScale = Style::StippleScaleMm(s->h); + auto export_style = [&](hStyle hs) { + Style *s = Style::Get(hs); + RgbaColor strokeRgb = Style::Color(hs, /*forExport=*/true); + RgbaColor fillRgb = Style::FillColor(hs, /*forExport=*/true); + StipplePattern pattern = Style::PatternType(hs); + double stippleScale = Style::StippleScaleMm(hs); - fprintf(f, ".s%x {\r\n", s->h.v); + fprintf(f, ".s%x {\r\n", hs.v); fprintf(f, "stroke:#%02x%02x%02x;\r\n", strokeRgb.red, strokeRgb.green, strokeRgb.blue); // don't know why we have to take a half of the width - fprintf(f, "stroke-width:%f;\r\n", Style::WidthMm(s->h.v) / 2.0); + fprintf(f, "stroke-width:%f;\r\n", Style::WidthMm(hs.v) / 2.0); fprintf(f, "stroke-linecap:round;\r\n"); fprintf(f, "stroke-linejoin:round;\r\n"); std::string patternStr = MakeStipplePattern(pattern, stippleScale, ',', @@ -1101,8 +1102,19 @@ void SvgFileWriter::StartFile() { if(!patternStr.empty()) { fprintf(f, "stroke-dasharray:%s;\r\n", patternStr.c_str()); } - fprintf(f, "fill:none;\r\n"); + if(s->filled) { + fprintf(f, "fill:#%02x%02x%02x;\r\n", fillRgb.red, fillRgb.green, fillRgb.blue); + } + else { + fprintf(f, "fill:none;\r\n"); + } fprintf(f, "}\r\n"); + }; + + export_style({Style::NO_STYLE}); + for(auto &style : SK.style) { + Style *s = &style; + export_style(s->h); } fprintf(f, "]]>\r\n"); } diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index 32b4b082..a7d44f12 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -1304,6 +1304,20 @@ c: break; case Command::CONSTRUCTION: { + // if we are drawing + if(SS.GW.pending.operation == Pending::DRAGGING_NEW_POINT || + SS.GW.pending.operation == Pending::DRAGGING_NEW_LINE_POINT || + SS.GW.pending.operation == Pending::DRAGGING_NEW_ARC_POINT || + SS.GW.pending.operation == Pending::DRAGGING_NEW_CUBIC_POINT || + SS.GW.pending.operation == Pending::DRAGGING_NEW_RADIUS) { + for(auto &hr : SS.GW.pending.requests) { + Request* r = SK.GetRequest(hr); + r->construction = !(r->construction); + SS.MarkGroupDirty(r->group); + } + SS.GW.Invalidate(); + break; + } SS.GW.GroupSelection(); if(SS.GW.gs.entities == 0) { Error(_("No entities are selected. Select entities before " diff --git a/src/mouse.cpp b/src/mouse.cpp index 263211da..77b52342 100644 --- a/src/mouse.cpp +++ b/src/mouse.cpp @@ -270,15 +270,16 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, return; } + if(pending.operation == Pending::DRAGGING_POINTS && ctrlDown) { + SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown); + SS.extraLine.ptB = UnProjectPoint(mp); + SS.extraLine.draw = true; + } + // We're currently dragging something; so do that. But if we haven't // painted since the last time we solved, do nothing, because there's // no sense solving a frame and not displaying it. if(!havePainted) { - if(pending.operation == Pending::DRAGGING_POINTS && ctrlDown) { - SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown); - SS.extraLine.ptB = UnProjectPoint(mp); - SS.extraLine.draw = true; - } return; } @@ -319,20 +320,16 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, // Don't start dragging the position about the normal // until we're a little ways out, to get a reasonable // reference pos - orig.mouse = mp; - break; + qt = Quaternion::IDENTITY; + } else { + double theta = atan2(orig.mouse.y-orig.mouseOnButtonDown.y, + orig.mouse.x-orig.mouseOnButtonDown.x); + theta -= atan2(y-orig.mouseOnButtonDown.y, + x-orig.mouseOnButtonDown.x); + + Vector gn = projRight.Cross(projUp); + qt = Quaternion::From(gn, -theta); } - double theta = atan2(orig.mouse.y-orig.mouseOnButtonDown.y, - orig.mouse.x-orig.mouseOnButtonDown.x); - theta -= atan2(y-orig.mouseOnButtonDown.y, - x-orig.mouseOnButtonDown.x); - - Vector gn = projRight.Cross(projUp); - qt = Quaternion::From(gn, -theta); - - SS.extraLine.draw = true; - SS.extraLine.ptA = UnProjectPoint(orig.mouseOnButtonDown); - SS.extraLine.ptB = UnProjectPoint(mp); } else { double dx = -(x - orig.mouse.x); double dy = -(y - orig.mouse.y); @@ -340,7 +337,6 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, qt = Quaternion::From(projUp, -s*dx).Times( Quaternion::From(projRight, s*dy)); } - orig.mouse = mp; // Now apply this rotation to the points being dragged. List *lhe = &(pending.points); @@ -353,18 +349,18 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, p = qt.Rotate(p); p = p.Plus(SS.extraLine.ptA); e->PointForceTo(p); - SS.MarkGroupDirtyByEntity(e->h); + } else { + UpdateDraggedPoint(*he, x, y); } - continue; + } else { + Quaternion q = e->PointGetQuaternion(); + Vector p = e->PointGetNum(); + q = qt.Times(q); + e->PointForceQuaternionTo(q); + // Let's rotate about the selected point; so fix up the + // translation so that that point didn't move. + e->PointForceTo(p); } - - Quaternion q = e->PointGetQuaternion(); - Vector p = e->PointGetNum(); - q = qt.Times(q); - e->PointForceQuaternionTo(q); - // Let's rotate about the selected point; so fix up the - // translation so that that point didn't move. - e->PointForceTo(p); SS.MarkGroupDirtyByEntity(e->h); } } else { @@ -373,8 +369,8 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, UpdateDraggedPoint(*he, x, y); SS.MarkGroupDirtyByEntity(*he); } - orig.mouse = mp; } + orig.mouse = mp; break; case Pending::DRAGGING_NEW_CUBIC_POINT: { @@ -1042,6 +1038,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my, bool shiftDown, bool ct ConstrainPointByHovered(hr.entity(1), &mouse); ClearSuper(); + AddToPending(hr); pending.operation = Pending::DRAGGING_NEW_RADIUS; pending.circle = hr.entity(0); diff --git a/src/platform/guigtk.cpp b/src/platform/guigtk.cpp index 1f0cc55d..94247b45 100644 --- a/src/platform/guigtk.cpp +++ b/src/platform/guigtk.cpp @@ -963,16 +963,17 @@ public: } void SetCursor(Cursor cursor) override { - Gdk::CursorType gdkCursorType; + std::string cursor_name; switch(cursor) { - case Cursor::POINTER: gdkCursorType = Gdk::ARROW; break; - case Cursor::HAND: gdkCursorType = Gdk::HAND1; break; + case Cursor::POINTER: cursor_name = "default"; break; + case Cursor::HAND: cursor_name = "pointer"; break; default: ssassert(false, "Unexpected cursor"); } auto gdkWindow = gtkWindow.get_gl_widget().get_window(); if(gdkWindow) { - gdkWindow->set_cursor(Gdk::Cursor::create(gdkCursorType)); + gdkWindow->set_cursor(Gdk::Cursor::create(gdkWindow->get_display(), cursor_name.c_str())); +// gdkWindow->get_display() } } diff --git a/src/platform/guiwin.cpp b/src/platform/guiwin.cpp index d8851958..b93b87b4 100644 --- a/src/platform/guiwin.cpp +++ b/src/platform/guiwin.cpp @@ -142,7 +142,18 @@ static std::string NegateMnemonics(const std::string &label) { return newLabel; } -static int Clamp(int x, int a, int b) { +static int Clamp(int x, int a, int b, int brda, int brdb) { + // If we are outside of an edge of the monitor + // and a "border" is requested "move in" from that edge + // by "b/brdX" (the "b" parameter is the resolution) + if((x <= a) && (brda)) { + a += b / brda; // yes "b/brda" since b is the size + } + + if(((x >= b) && brdb)) { + b -= b / brdb; + } + return max(a, min(x, b)); } @@ -1084,7 +1095,7 @@ public: return 0; } } else if(wParam == VK_ESCAPE) { - sscheck(SendMessageW(hWindow, msg, wParam, lParam)); + window->HideEditor(); return 0; } } @@ -1218,11 +1229,14 @@ public: sscheck(GetMonitorInfo(MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST), &mi)); // If it somehow ended up off-screen, then put it back. + // and make it visible by at least this portion of the scrren + const LONG movein = 40; + RECT mrc = mi.rcMonitor; - rc.left = Clamp(rc.left, mrc.left, mrc.right); - rc.right = Clamp(rc.right, mrc.left, mrc.right); - rc.top = Clamp(rc.top, mrc.top, mrc.bottom); - rc.bottom = Clamp(rc.bottom, mrc.top, mrc.bottom); + rc.left = Clamp(rc.left, mrc.left, mrc.right, 0, movein); + rc.right = Clamp(rc.right, mrc.left, mrc.right, movein, 0); + rc.top = Clamp(rc.top, mrc.top, mrc.bottom, 0, movein); + rc.bottom = Clamp(rc.bottom, mrc.top, mrc.bottom, movein, 0); // And make sure the minimum size is respected. (We can freeze a size smaller // than minimum size if the DPI changed between runs.) diff --git a/src/sketch.h b/src/sketch.h index 83773749..68a912b3 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -790,9 +790,9 @@ public: static hConstraint TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB, hEntity entityA, hEntity entityB = Entity::NO_ENTITY, bool other = false, bool other2 = false); - static void ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc); - static void ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic); - static void ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB); + static bool ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc); + static bool ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic); + static bool ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB); }; class hEquation { @@ -883,6 +883,7 @@ public: RgbaColor color; double width; int zIndex; + bool exportable; } Default; static const Default Defaults[]; @@ -890,6 +891,7 @@ public: static std::string CnfWidth(const std::string &prefix); static std::string CnfTextHeight(const std::string &prefix); static std::string CnfPrefixToName(const std::string &prefix); + static std::string CnfExportable(const std::string &prefix); static void CreateAllDefaultStyles(); static void CreateDefaultStyle(hStyle h); diff --git a/src/style.cpp b/src/style.cpp index 1f719f67..19a1835c 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -8,22 +8,22 @@ #include "solvespace.h" const Style::Default Style::Defaults[] = { - { { ACTIVE_GRP }, "ActiveGrp", RGBf(1.0, 1.0, 1.0), 1.5, 4 }, - { { CONSTRUCTION }, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, 0 }, - { { INACTIVE_GRP }, "InactiveGrp", RGBf(0.5, 0.3, 0.0), 1.5, 3 }, - { { DATUM }, "Datum", RGBf(0.0, 0.8, 0.0), 1.5, 0 }, - { { SOLID_EDGE }, "SolidEdge", RGBf(0.8, 0.8, 0.8), 1.0, 2 }, - { { CONSTRAINT }, "Constraint", RGBf(1.0, 0.1, 1.0), 1.0, 0 }, - { { SELECTED }, "Selected", RGBf(1.0, 0.0, 0.0), 1.5, 0 }, - { { HOVERED }, "Hovered", RGBf(1.0, 1.0, 0.0), 1.5, 0 }, - { { CONTOUR_FILL }, "ContourFill", RGBf(0.0, 0.1, 0.1), 1.0, 0 }, - { { NORMALS }, "Normals", RGBf(0.0, 0.4, 0.4), 1.0, 0 }, - { { ANALYZE }, "Analyze", RGBf(0.0, 1.0, 1.0), 3.0, 0 }, - { { DRAW_ERROR }, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, 0 }, - { { DIM_SOLID }, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, 0 }, - { { HIDDEN_EDGE }, "HiddenEdge", RGBf(0.8, 0.8, 0.8), 1.0, 1 }, - { { OUTLINE }, "Outline", RGBf(0.8, 0.8, 0.8), 3.0, 5 }, - { { 0 }, NULL, RGBf(0.0, 0.0, 0.0), 0.0, 0 } + { { ACTIVE_GRP }, "ActiveGrp", RGBf(1.0, 1.0, 1.0), 1.5, 4, true }, + { { CONSTRUCTION }, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, 0, false }, + { { INACTIVE_GRP }, "InactiveGrp", RGBf(0.5, 0.3, 0.0), 1.5, 3, true }, + { { DATUM }, "Datum", RGBf(0.0, 0.8, 0.0), 1.5, 0, true }, + { { SOLID_EDGE }, "SolidEdge", RGBf(0.8, 0.8, 0.8), 1.0, 2, true }, + { { CONSTRAINT }, "Constraint", RGBf(1.0, 0.1, 1.0), 1.0, 0, true }, + { { SELECTED }, "Selected", RGBf(1.0, 0.0, 0.0), 1.5, 0, true }, + { { HOVERED }, "Hovered", RGBf(1.0, 1.0, 0.0), 1.5, 0, true }, + { { CONTOUR_FILL }, "ContourFill", RGBf(0.0, 0.1, 0.1), 1.0, 0, true }, + { { NORMALS }, "Normals", RGBf(0.0, 0.4, 0.4), 1.0, 0, true }, + { { ANALYZE }, "Analyze", RGBf(0.0, 1.0, 1.0), 3.0, 0, true }, + { { DRAW_ERROR }, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, 0, true }, + { { DIM_SOLID }, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, 0, true }, + { { HIDDEN_EDGE }, "HiddenEdge", RGBf(0.8, 0.8, 0.8), 1.0, 1, true }, + { { OUTLINE }, "Outline", RGBf(0.8, 0.8, 0.8), 3.0, 5, true }, + { { 0 }, NULL, RGBf(0.0, 0.0, 0.0), 0.0, 0, true } }; std::string Style::CnfColor(const std::string &prefix) { @@ -35,6 +35,9 @@ std::string Style::CnfWidth(const std::string &prefix) { std::string Style::CnfTextHeight(const std::string &prefix) { return "Style_" + prefix + "_TextHeight"; } +std::string Style::CnfExportable(const std::string &prefix) { + return "Style_" + prefix + "_Exportable"; +} std::string Style::CnfPrefixToName(const std::string &prefix) { std::string name = "#def-"; @@ -97,7 +100,9 @@ void Style::FillDefaultStyle(Style *s, const Default *d, bool factory) { s->textOrigin = TextOrigin::NONE; s->textAngle = 0; s->visible = true; - s->exportable = true; + s->exportable = (factory) + ? d->exportable + : settings->ThawBool(CnfExportable(d->cnfPrefix), d->exportable); s->filled = false; s->fillColor = RGBf(0.3, 0.3, 0.3); s->stippleType = (d->h.v == Style::HIDDEN_EDGE) ? StipplePattern::DASH @@ -121,6 +126,7 @@ void Style::FreezeDefaultStyles(Platform::SettingsRef settings) { settings->FreezeColor(CnfColor(d->cnfPrefix), Color(d->h)); settings->FreezeFloat(CnfWidth(d->cnfPrefix), (float)Width(d->h)); settings->FreezeFloat(CnfTextHeight(d->cnfPrefix), (float)TextHeight(d->h)); + settings->FreezeBool(CnfExportable(d->cnfPrefix), Exportable(d->h.v)); } } @@ -850,17 +856,19 @@ void TextWindow::ShowStyleInfo() { ((uint32_t)s->textOrigin & (uint32_t)Style::TextOrigin::TOP) ? RADIO_TRUE : RADIO_FALSE); } - if(s->h.v >= Style::FIRST_CUSTOM) { - Printf(false, ""); + Printf(false, ""); + if(s->h.v >= Style::FIRST_CUSTOM) { Printf(false, " %Fd%D%f%Lv%s show these objects on screen%E", s->h.v, &ScreenChangeStyleYesNo, s->visible ? CHECK_TRUE : CHECK_FALSE); + } - Printf(false, " %Fd%D%f%Le%s export these objects%E", - s->h.v, &ScreenChangeStyleYesNo, - s->exportable ? CHECK_TRUE : CHECK_FALSE); + Printf(false, " %Fd%D%f%Le%s export these objects%E", + s->h.v, &ScreenChangeStyleYesNo, + s->exportable ? CHECK_TRUE : CHECK_FALSE); + if(s->h.v >= Style::FIRST_CUSTOM) { Printf(false, ""); Printf(false, "To assign lines or curves to this style,"); Printf(false, "right-click them on the drawing.");