diff --git a/.travis.yml b/.travis.yml index 5e831b192..b51c80c70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,18 +11,6 @@ script: - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./.travis/build-debian.sh; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ./.travis/build-macos.sh; fi deploy: - # Releases to solvespace/solvespace - - provider: releases - api_key: - secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM= - skip_cleanup: true - file_glob: true - file: - - ../*.deb - on: - repo: solvespace/solvespace - tags: true - condition: "$TRAVIS_OS_NAME == linux" - provider: releases api_key: secure: dDlkIawHcODlW9B/20/cQCtzeoocvs0hKuNngRKXKqzXLWTRq33oq/B7+39tAixWbmv6exTpijiKrRNFiSCW5Z4iwHLwaRD4XJznxw63e/Hus/dxg2Tvqx7XFpkCz8mT1Z+gZQE5YxAngeZPpI/sZbZtF1UO3yH5eLeeokZ15p26ZskQUPoYuzrTgTzYL3XfpG3F+20rNBawH1ycsCTVD/08/n31d2m3CrKAsbW7er92ek6w4fzKr7NW8WeXjrPJETVpw5fQg1Od3pRGW8dPQaJcvKQEogMp8Mm0ETYd0qigg89/giBz7QwOgmAWQ4dH+DfZH4Ojl//127QztBolMvyDMQBykWrtJoGcij05sT6K2IJr2FHeUBO12MAEdjiVvhQj3DtTzjPiZAHHDBSLWxLKWWhlhHE4pq7g1MQhqXkaAHI2BLNzwLmaowbMT0bECf9yfz6xx18h6XPQFX44oOktraobVALFlyHqeKa8zdcUt22LF6uAL1m5dxL0tny3eXCIPE4UH/RZgua/cHV9G3cUvKQa/QnFSLRhvWVSbGB+7YsHouBJcsUOOW1gmd5442XuC7mpppccRldh+GSxUk6TBJRAx7TeQ0ybDUaoco9MUqp2twv3KreR2+8Q12PDaAhfQVNEGdF3wTm1sShImjCN4VN3eSLlBEbve1QRQXM= @@ -32,25 +20,3 @@ deploy: repo: solvespace/solvespace tags: true condition: "$TRAVIS_OS_NAME == osx" - # Releases to whitequark/solvespace (to be removed) - - provider: releases - api_key: - secure: DA3tW0My37vbi2t3dZ061281Xm8KSIkeLdFZsQISrut0g1kkbWuBTPxAfvE3B6OE8p47wAclE/wxA1+obMTVkY0oYpd5u+JelYNHxU/oL8Ww0xdUANwKNJ1JD2EZP8nSz7JSvxuGILC6AFPoTjawsG97SXwiTyp7z0PA6nvzraE= - skip_cleanup: true - file_glob: true - file: - - ../*.deb - on: - repo: whitequark/solvespace - tags: true - condition: "$TRAVIS_OS_NAME == linux" - - provider: releases - api_key: - secure: DA3tW0My37vbi2t3dZ061281Xm8KSIkeLdFZsQISrut0g1kkbWuBTPxAfvE3B6OE8p47wAclE/wxA1+obMTVkY0oYpd5u+JelYNHxU/oL8Ww0xdUANwKNJ1JD2EZP8nSz7JSvxuGILC6AFPoTjawsG97SXwiTyp7z0PA6nvzraE= - skip_cleanup: true - file: build/solvespace.dmg - on: - repo: whitequark/solvespace - tags: true - condition: "$TRAVIS_OS_NAME == osx" - diff --git a/.travis/build-debian.sh b/.travis/build-debian.sh index 124e45bae..b3ac2cb55 100755 --- a/.travis/build-debian.sh +++ b/.travis/build-debian.sh @@ -2,5 +2,7 @@ if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=Debug; fi -export BUILD_TYPE -dpkg-buildpackage -b -us -uc +mkdir build +cd build +cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE +make VERBOSE=1 diff --git a/.travis/install-macos.sh b/.travis/install-macos.sh index 6fb5a4f72..1214dd4f6 100755 --- a/.travis/install-macos.sh +++ b/.travis/install-macos.sh @@ -1,4 +1,3 @@ #!/bin/sh -xe brew update -brew upgrade cmake libpng diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..a05b9828d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,134 @@ +Changelog +========= + +2.x +--- + +Bug fixes: + * Do not crash when changing an unconstrained lathe group between + union and difference modes. + +2.3 +--- + +Bug fixes: + * Do not crash when applying a symmetry constraint to two points. + * Fix TTF font metrics again (properly this time). + * Fix the "draw back faces in red" option. + * Fix export of wireframe as 3D DXF. + * Various minor crashes. + +2.2 +--- + +Other new features: + * OS X: support 3Dconnexion devices (SpaceMouse, SpaceNavigator, etc). + * GTK: files with uppercase extensions can be opened. + +Bug fixes: + * Do not remove autosaves after successfully opening a file, preventing + data loss in case of two abnormal terminations in a row. + * Do not crash when changing autosave interval. + * Unbreak the "Show degrees of freedom" command. + * Three.js: correctly respond to controls when browser zoom is used. + * OS X: do not completely hide main window when defocused. + * GTK: unbreak 3Dconnexion support. + * When pasting transformed entities, multiply constraint values by scale. + * Fix TTF font metrics (restore the behavior from version 2.0). + * Forcibly show the current group once we start a drawing operation. + * DXF export: always declare layers before using them. + * Do not truncate operations on selections to first 32 selected entities. + * Translate and rotate groups inherit the "suppress solid model" setting. + * DXF: files with paths containing non-ASCII or spaces can be exported + or imported. + * Significantly improved performance when dragging an entity. + * Various crashes and minor glitches. + +2.1 +--- + +New sketch features: + * Lathe groups create circle and face entities. + * New toolbar button for creating lathe groups. + * Chord tolerance is separated into two: display chord tolerance (specified + in percents, relative to model bounding box), and export chord tolerance + (specified in millimeters as absolute value). + * Bezier spline points can be added and removed after the spline is created. + * When an unconstrained extrusion is switched between "union" and + "difference", its normal is flipped. + * Groups can be added in the middle of the stack. Note that this results + in files incompatible with version 2.0. + * Active group can be removed. + * Removing an imported group does not cause all subsequent groups to also + be removed. + * When a new group with a solid is created, the color is taken from + a previous group with a solid, if any. + * Entities in a newly active group do not become visible. + * When entities are selected, "Zoom to fit" zooms to fit only these + entities and not the entire sketch. + * Zero-length edges are reported with a "zero-length error", not + "points not all coplanar". + +New constraint features: + * Height of the font used for drawing constraint labels can be changed. + * New constraint, length difference, placed with J. + (Patch by Peter Ruevski) + * Horizontal/vertical constraints are automatically added if a line segment + is close enough to being horizontal/vertical. This can be disabled by + holding Ctrl. + * Reference dimensions and angles can be placed with Shift+D and Shift+N. + * Copying and pasting entities duplicates any constraints that only involve + entities in the clipboard, as well as selected comments. + * Diameter constraints can be shown as radius. + * The "pi" identifier can be used in expressions. + * Constraint labels can be snapped to grid. + * Integer angles are displayed without trailing zeroes. + * Angle constraints have proper reference lines and arrowheads. + * Extension lines are drawn for point-line distance constraints. + +New solver features: + * Sketches with redundant and unsolvable constraints are distinguished. + * New group setting, "allow redundant constraints". Note that it makes + the solver less stable. + +New rendering and styling features: + * New line style parameter: stippling, based on ISO 128. + * Outlines of solids can be drawn in a particular style (by default, thick + lines) controlled by the "Show outline of solid model" button. + * Occluded edges can be drawn in a particular style (by default, stippled + with short dashes) controlled by the "Show hidden lines" button. + * Solids can be made transparent. + +New export/import features: + * The old "import" command (for .slvs files) is renamed to "link". + * If a linked .slvs file is not found, first the relative path recorded + in the .slvs file is checked and then the absolute path; this is + an inversion of the previously used order. If it is still not found, + a dialog appears offering to locate it. + * DXF and DWG files can be imported, with point-coincident, horizontal and + vertical constraints automatically inferred from geometry, and distance + and angle constraints created when a dimension placed against geometry + exists. + * Triangle mesh can be exported for viewing in the browser through WebGL. + * Export dialogs remember the last file format used, and preselect it. + * Exported DXF files have exact circles, arcs and splines instead of + a piecewise linear approximation (unless hidden line removal was needed). + * Exported DXF files preserve color and line thickness. + * In exported DXF files, constraints are represented as DXF dimensions, + instead of piecewise linear geometry. + * When exporting 2d views, overlapping lines are removed. + +Other new features: + * Native Linux (GTK 2 and GTK 3) and Mac OS X ports. + * Automatically save and then restore sketches if SolveSpace crashes. + (Patch by Marc Britten) + * Unicode is supported everywhere (filenames, group names, TTF text, + comments), although RTL scripts and scripts making heavy use of ligatures + are not rendered correctly. + * The vector font is grid-fitted when rendered on screen to make it easier + to read regardless of its size. + +2.0 +--- + +Initial public release. diff --git a/CMakeLists.txt b/CMakeLists.txt index 401d71134..ea464e587 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,11 +17,16 @@ set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX # project +# NOTE TO PACKAGERS: The embedded git commit hash is critical for rapid bug triage when the builds +# can come from a variety of sources. If you are mirroring the sources or otherwise build when +# the .git directory is not present, please comment the following line: include(GetGitCommitHash) +# and instead uncomment the following, adding the complete git hash of the checkout you are using: +# set(GIT_COMMIT_HASH 0000000000000000000000000000000000000000) project(solvespace) set(solvespace_VERSION_MAJOR 2) -set(solvespace_VERSION_MINOR 1) +set(solvespace_VERSION_MINOR 3) string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH) if(NOT WIN32 AND NOT APPLE) @@ -154,6 +159,8 @@ if(WIN32) "${CMAKE_SOURCE_DIR}/extlib/si/siapp.lib") endif() elseif(APPLE) + set(CMAKE_FIND_FRAMEWORK LAST) + find_package(PNG REQUIRED) find_package(Freetype REQUIRED) find_library(APPKIT_LIBRARY AppKit REQUIRED) diff --git a/README.md b/README.md index a1a49ec26..838b92fab 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,13 @@ Building on Linux ### Building for Linux You will need CMake, libpng, zlib, json-c, fontconfig, freetype, gtkmm 2.4, -pangomm 1.4, OpenGL and OpenGL GLU. +pangomm 1.4, OpenGL, OpenGL GLU and OpenGL GLEW, and optionally, the Space Navigator +client library. On a Debian derivative (e.g. Ubuntu) these can be installed with: apt-get install libpng12-dev libjson-c-dev libfreetype6-dev \ libfontconfig1-dev libgtkmm-2.4-dev libpangomm-1.4-dev \ - libgl-dev libglu-dev libglew-dev cmake + libgl-dev libglu-dev libglew-dev libspnav-dev cmake Before building, check out the necessary submodules: diff --git a/appveyor.yml b/appveyor.yml index 8078a5655..4f4b3ae17 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.1.{build} +version: 2.2.{build} clone_depth: 1 before_build: - git submodule update --init @@ -19,7 +19,6 @@ artifacts: - path: build\src\RelWithDebInfo\solvespace.pdb name: solvespace.pdb deploy: - # Releases to solvespace/solvespace - provider: GitHub auth_token: secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC @@ -27,11 +26,3 @@ deploy: artifact: solvespace.exe on: appveyor_repo_tag: true - # Releases to whitequark/solvespace (to be removed) - - provider: GitHub - auth_token: - secure: Flqxu1cz6PyxVT1wzTP4bSrQOY8wFrO7pJxYxvjEkLqIUU4dsDQrs2rac/A9deet - description: "" - artifact: solvespace.exe - on: - appveyor_repo_tag: true diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index a561717cb..000000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -solvespace (2.1) unstable; urgency=low - - * Initial Release. - - -- whitequark Fri, 20 Mar 2015 12:39:28 +0300 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec635144f..000000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control deleted file mode 100644 index 30e8c9727..000000000 --- a/debian/control +++ /dev/null @@ -1,73 +0,0 @@ -Source: solvespace -Section: graphics -Priority: optional -Maintainer: whitequark -Build-Depends: debhelper (>= 9), cmake, libpng12-dev, zlib1g-dev, libjson-c-dev, - libfontconfig1-dev, libgtkmm-2.4-dev, libpangomm-1.4-dev, - libgl-dev, libglu-dev, libglew-dev -Standards-Version: 3.9.5 -Homepage: http://solvespace.com -Vcs-Git: git://github.com/whitequark/solvespace -Vcs-Browser: https://github.com/whitequark/solvespace - -Package: solvespace -Architecture: any -Multi-Arch: foreign -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: SolveSpace parametric 2d/3d CAD - SolveSpace is a parametric 2d/3d CAD program. Applications include: - . - * modeling 3d parts — draw with extrudes, revolves, and Boolean - (union / difference) operations; - * modeling 2d parts — draw the part as a single section, and export DXF, - PDF, SVG; use 3d assembly to verify fit; - * 3d-printed parts — export the STL or other triangle mesh expected by - most 3d printers; - * preparing CAM data — export 2d vector art for a waterjet machine or - laser cutter; or generate STEP or STL, for import into third-party - CAM software for machining; - * mechanism design — use the constraint solver to simulate planar or - spatial linkages, with pin, ball, or slide joints; - * plane and solid geometry — replace hand-solved trigonometry and - spreadsheets with a live dimensioned drawing. - -Package: solvespace-dbg -Architecture: any -Section: debug -Priority: extra -Depends: solvespace (= ${binary:Version}), ${misc:Depends} -Description: SolveSpace parametric 2d/3d CAD (debugging files) - SolveSpace is a parametric 2d/3d CAD. - . - This package contains the debugging symbols for solvespace. - -Package: libslvs1 -Section: libs -Architecture: any -Multi-Arch: same -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: SolveSpace geometric kernel - SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric - kernel of SolveSpace, built as a library. - -Package: libslvs1-dev -Section: libs -Architecture: any -Multi-Arch: same -Depends: libslvs1, ${misc:Depends} -Description: SolveSpace geometric kernel (development files) - SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric - kernel of SolveSpace, built as a library. - . - This package includes development files for libslvs. - -Package: libslvs1-dbg -Architecture: any -Section: debug -Priority: extra -Depends: libslvs1 (= ${binary:Version}), ${misc:Depends} -Description: SolveSpace geometric kernel (debugging files) - SolveSpace is a parametric 2d/3d CAD. libslvs contains the geometric - kernel of SolveSpace, built as a library. - . - This package contains the debugging symbols for libslvs1. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 8740eb7a1..000000000 --- a/debian/copyright +++ /dev/null @@ -1,33 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: solvespace -Source: https://github.com/whitequark/solvespace - -Files: * -Copyright: 2008-2013 Jonathan Westhues. -License: GPL-3.0+ - -Files: debian/* -Copyright: 2015 Peter Zotov -License: GPL-3.0+ - -License: GPL-3.0+ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see . - . - On Debian systems, the complete text of the GNU General - Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". - -# Please also look if there are files or directories which have a -# different copyright/license attached and list them here. -# Please avoid to pick license terms that are more restrictive than the -# packaged work, as it may make Debian's contributions unacceptable upstream. diff --git a/debian/docs b/debian/docs deleted file mode 100644 index 887d73178..000000000 --- a/debian/docs +++ /dev/null @@ -1,2 +0,0 @@ -COPYING.txt -README.md diff --git a/debian/libslvs1-dev.install b/debian/libslvs1-dev.install deleted file mode 100644 index 7adf7a612..000000000 --- a/debian/libslvs1-dev.install +++ /dev/null @@ -1 +0,0 @@ -usr/include/slvs.h diff --git a/debian/libslvs1.install b/debian/libslvs1.install deleted file mode 100644 index 0869500e6..000000000 --- a/debian/libslvs1.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/**/libslvs.so* diff --git a/debian/menu b/debian/menu deleted file mode 100644 index d8b2603e1..000000000 --- a/debian/menu +++ /dev/null @@ -1,7 +0,0 @@ -?package(solvespace):needs="X11" section="Applications/Graphics" \ - title="SolveSpace" command="/usr/bin/solvespace" \ - hints="CAD" \ - icon16x16="/usr/share/pixmaps/solvespace-16x16.xpm" \ - icon24x24="/usr/share/pixmaps/solvespace-24x24.xpm" \ - icon32x32="/usr/share/pixmaps/solvespace-32x32.xpm" \ - icon48x48="/usr/share/pixmaps/solvespace-48x48.xpm" diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 084b447bf..000000000 --- a/debian/rules +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/make -f -# See debhelper(7) (uncomment to enable) -# output every command that modifies files on the build system. -#DH_VERBOSE = 1 - -# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* -DPKG_EXPORT_BUILDFLAGS = 1 -include /usr/share/dpkg/default.mk - -# main packaging script based on dh7 syntax -%: - dh $@ - -# debmake generated override targets -# This is example for Cmake (See http://bugs.debian.org/641051 ) -override_dh_auto_configure: - dh_auto_configure -- \ - -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \ - -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) - -# create a -dbg package -override_dh_strip: - dh_strip -psolvespace --dbg-package=solvespace-dbg - dh_strip -plibslvs1 --dbg-package=libslvs1-dbg diff --git a/debian/solvespace.install b/debian/solvespace.install deleted file mode 100644 index ff23693b3..000000000 --- a/debian/solvespace.install +++ /dev/null @@ -1,3 +0,0 @@ -usr/bin/solvespace -usr/share/icons -usr/share/applications diff --git a/debian/solvespace.sharedmimeinfo b/debian/solvespace.sharedmimeinfo deleted file mode 100644 index 4f6e2cf52..000000000 --- a/debian/solvespace.sharedmimeinfo +++ /dev/null @@ -1,8 +0,0 @@ - - - - SolveSpace sketch - - - - diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 89ae9db8f..000000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/debian/source/options b/debian/source/options deleted file mode 100644 index 3fbd3a471..000000000 --- a/debian/source/options +++ /dev/null @@ -1,3 +0,0 @@ -tar-ignore = "*.sublime-*" -tar-ignore = "build*" -tar-ignore = ".git" diff --git a/extlib/libdxfrw b/extlib/libdxfrw index 8d24e656f..8f958955f 160000 --- a/extlib/libdxfrw +++ b/extlib/libdxfrw @@ -1 +1 @@ -Subproject commit 8d24e656fbd293cb953828389d01d362f2a1a8e0 +Subproject commit 8f958955f54668c142ded760dc951ffd16d9c71b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e15e96b4..5c5313033 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -342,8 +342,9 @@ if(APPLE) set(fixups) foreach(lib ${platform_BUNDLED_LIBS}) get_filename_component(name ${lib} NAME) - execute_process(COMMAND otool -XD ${lib} + execute_process(COMMAND otool -D ${lib} OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib}) add_custom_command(TARGET solvespace POST_BUILD COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name} $ @@ -380,6 +381,10 @@ foreach(SIZE 16x16 24x24 32x32 48x48) DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/${SIZE}/mimetypes RENAME application.x-solvespace.png) endforeach() +foreach(SIZE 16x16 24x24 32x32 48x48) + install(FILES unix/solvespace-${SIZE}.xpm + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps/) +endforeach() # valgrind diff --git a/src/clipboard.cpp b/src/clipboard.cpp index a6be42003..c13b4fb50 100644 --- a/src/clipboard.cpp +++ b/src/clipboard.cpp @@ -117,6 +117,15 @@ void GraphicsWindow::CopySelection(void) { SS.clipboard.r.Add(&cr); } + for(Selection *s = ls->First(); s; s = ls->NextAfter(s)) { + if(!s->constraint.v) continue; + + Constraint *c = SK.GetConstraint(s->constraint); + if(c->type == Constraint::COMMENT) { + SS.clipboard.c.Add(c); + } + } + Constraint *c; for(c = SK.constraint.First(); c; c = SK.constraint.NextAfter(c)) { if(!SS.clipboard.ContainsEntity(c->ptA) || @@ -124,7 +133,8 @@ void GraphicsWindow::CopySelection(void) { !SS.clipboard.ContainsEntity(c->entityA) || !SS.clipboard.ContainsEntity(c->entityB) || !SS.clipboard.ContainsEntity(c->entityC) || - !SS.clipboard.ContainsEntity(c->entityD)) { + !SS.clipboard.ContainsEntity(c->entityD) || + c->type == Constraint::COMMENT) { continue; } SS.clipboard.c.Add(c); @@ -201,7 +211,27 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) { c.other2 = cc->other2; c.reference = cc->reference; c.disp = cc->disp; - Constraint::AddConstraint(&c, /*rememberForUndo=*/false); + c.comment = cc->comment; + switch(c.type) { + case Constraint::COMMENT: + c.disp.offset = c.disp.offset.Plus(trans); + break; + + case Constraint::PT_PT_DISTANCE: + case Constraint::PT_LINE_DISTANCE: + case Constraint::PROJ_PT_DISTANCE: + case Constraint::DIAMETER: + c.valA *= fabs(scale); + break; + + default: + break; + } + + hConstraint hc = Constraint::AddConstraint(&c, /*rememberForUndo=*/false); + if(c.type == Constraint::COMMENT) { + MakeSelected(hc); + } } SS.ScheduleGenerateAll(); diff --git a/src/cocoa/cocoamain.mm b/src/cocoa/cocoamain.mm index c111ed434..1b6d3e6c3 100644 --- a/src/cocoa/cocoamain.mm +++ b/src/cocoa/cocoamain.mm @@ -221,6 +221,9 @@ - (void)drawRect:(NSRect)aRect { CGContextDrawImage((CGContextRef) [[NSGraphicsContext currentContext] graphicsPort], [self bounds], image); + + CGImageRelease(image); + CGDataProviderRelease(provider); } - (void)drawGL { @@ -371,8 +374,6 @@ - (void)keyDown:(NSEvent*)event { if(NSString *nsChr = [event charactersIgnoringModifiers]) chr = [nsChr characterAtIndex:0]; - if(chr == NSDeleteCharacter) /* map delete back to backspace */ - chr = '\b'; if(chr >= NSF1FunctionKey && chr <= NSF12FunctionKey) chr = SolveSpace::GraphicsWindow::FUNCTION_KEY_BASE + (chr - NSF1FunctionKey); @@ -397,7 +398,7 @@ - (void)startEditing:(NSString*)text at:(NSPoint)xy withHeight:(double)fontHeigh .x = xy.x + size.width / 2, .y = xy.y - size.height / 2 }; - [[self window] becomeKeyWindow]; + [[self window] makeKeyWindow]; [super startEditing:text at:[self convertPointFromBacking:point] withHeight:fontHeight usingMonospace:FALSE]; [self prepareEditorWithMinWidthInChars:minWidthChars]; @@ -647,12 +648,15 @@ void InitMainMenu(NSMenu *mainMenu) { label = [[NSString stringWithUTF8String:entry->label] stringByReplacingOccurrencesOfString:@"&" withString:@""]; - unichar accel_char = entry->accel & + unichar accelChar = entry->accel & ~(GraphicsWindow::SHIFT_MASK | GraphicsWindow::CTRL_MASK); - if(accel_char > GraphicsWindow::FUNCTION_KEY_BASE && - accel_char <= GraphicsWindow::FUNCTION_KEY_BASE + 12) - accel_char = NSF1FunctionKey + (accel_char - GraphicsWindow::FUNCTION_KEY_BASE - 1); - NSString *accel = [NSString stringWithCharacters:&accel_char length:1]; + if(accelChar > GraphicsWindow::FUNCTION_KEY_BASE && + accelChar <= GraphicsWindow::FUNCTION_KEY_BASE + 12) { + accelChar = NSF1FunctionKey + (accelChar - GraphicsWindow::FUNCTION_KEY_BASE - 1); + } else if(accelChar == GraphicsWindow::DELETE_KEY) { + accelChar = NSBackspaceCharacter; + } + NSString *accel = [NSString stringWithCharacters:&accelChar length:1]; menuItem = [levels[entry->level] addItemWithTitle:label action:NULL keyEquivalent:[accel lowercaseString]]; @@ -806,6 +810,9 @@ - (void)setIndex:(NSInteger)newIndex { if(defExtension != "") { extensionIndex = [extensions indexOfObject: [NSString stringWithUTF8String:defExtension.c_str()]]; + if(extensionIndex == -1) { + extensionIndex = 0; + } } [button selectItemAtIndex:extensionIndex]; @@ -1021,16 +1028,16 @@ void InitTextWindow() { NSUtilityWindowMask)]; [[TW standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[TW standardWindowButton:NSWindowZoomButton] setHidden:YES]; - [TW setTitle:@"Browser"]; + [TW setTitle:@"Property Browser"]; [TW setFrameAutosaveName:@"TextWindow"]; [TW setFloatingPanel:YES]; [TW setBecomesKeyOnlyIfNeeded:YES]; - [GW addChildWindow:TW ordered:NSWindowAbove]; NSScrollView *scrollView = [[NSScrollView alloc] init]; [TW setContentView:scrollView]; [scrollView setBackgroundColor:[NSColor blackColor]]; [scrollView setHasVerticalScroller:YES]; + [scrollView setScrollerKnobStyle:NSScrollerKnobStyleLight]; [[scrollView contentView] setCopiesOnScroll:YES]; TWView = [[TextWindowView alloc] init]; @@ -1089,6 +1096,7 @@ bool TextEditControlIsVisible(void) { void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error) { NSAlert *alert = [[NSAlert alloc] init]; [alert setAlertStyle:(error ? NSWarningAlertStyle : NSInformationalAlertStyle)]; + [alert addButtonWithTitle:@"OK"]; /* do some additional formatting of the message these are heuristics, but they are made failsafe and lead to nice results. */ @@ -1153,8 +1161,6 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende } - (void)applicationWillTerminate:(NSNotification *)aNotification { - SolveSpace::SK.Clear(); - SolveSpace::SS.Clear(); SolveSpace::SS.Exit(); } @@ -1172,6 +1178,155 @@ - (IBAction)preferences:(id)sender { [NSApp stop:nil]; } +/* + * Normally we would just link to the 3DconnexionClient framework. + * We don't want to (are not allowed to) distribute the official + * framework, so we're trying to use the one installed on the users + * computer. There are some different versions of the framework, + * the official one and re-implementations using an open source driver + * for older devices (spacenav-plus). So weak-linking isn't an option, + * either. The only remaining way is using CFBundle to dynamically + * load the library at runtime, and also detect its availability. + * + * We're also defining everything needed from the 3DconnexionClientAPI, + * so we're not depending on the API headers. + */ + +#pragma pack(push,2) + +enum { + kConnexionClientModeTakeOver = 1, + kConnexionClientModePlugin = 2 +}; + +#define kConnexionMsgDeviceState '3dSR' +#define kConnexionMaskButtons 0x00FF +#define kConnexionMaskAxis 0x3F00 + +typedef struct { + uint16_t version; + uint16_t client; + uint16_t command; + int16_t param; + int32_t value; + UInt64 time; + uint8_t report[8]; + uint16_t buttons8; + int16_t axis[6]; + uint16_t address; + uint32_t buttons; +} ConnexionDeviceState, *ConnexionDeviceStatePtr; + +#pragma pack(pop) + +typedef void (*ConnexionAddedHandlerProc)(io_connect_t); +typedef void (*ConnexionRemovedHandlerProc)(io_connect_t); +typedef void (*ConnexionMessageHandlerProc)(io_connect_t, natural_t, void *); + +typedef OSErr (*InstallConnexionHandlersProc)(ConnexionMessageHandlerProc, ConnexionAddedHandlerProc, ConnexionRemovedHandlerProc); +typedef void (*CleanupConnexionHandlersProc)(void); +typedef UInt16 (*RegisterConnexionClientProc)(UInt32, UInt8 *, UInt16, UInt32); +typedef void (*UnregisterConnexionClientProc)(UInt16); + +static BOOL connexionShiftIsDown = NO; +static UInt16 connexionClient = 0; +static UInt32 connexionSignature = 'SoSp'; +static UInt8 *connexionName = (UInt8 *)"SolveSpace"; +static CFBundleRef spaceBundle = NULL; +static InstallConnexionHandlersProc installConnexionHandlers = NULL; +static CleanupConnexionHandlersProc cleanupConnexionHandlers = NULL; +static RegisterConnexionClientProc registerConnexionClient = NULL; +static UnregisterConnexionClientProc unregisterConnexionClient = NULL; + +static void connexionAdded(io_connect_t con) {} +static void connexionRemoved(io_connect_t con) {} +static void connexionMessage(io_connect_t con, natural_t type, void *arg) { + if (type != kConnexionMsgDeviceState) { + return; + } + + ConnexionDeviceState *device = (ConnexionDeviceState *)arg; + + dispatch_async(dispatch_get_main_queue(), ^(void){ + SolveSpace::SS.GW.SpaceNavigatorMoved( + (double)device->axis[0] * -0.25, + (double)device->axis[1] * -0.25, + (double)device->axis[2] * 0.25, + (double)device->axis[3] * -0.0005, + (double)device->axis[4] * -0.0005, + (double)device->axis[5] * -0.0005, + (connexionShiftIsDown == YES) ? 1 : 0 + ); + }); +} + +static void connexionInit() { + NSString *bundlePath = @"/Library/Frameworks/3DconnexionClient.framework"; + NSURL *bundleURL = [NSURL fileURLWithPath:bundlePath]; + spaceBundle = CFBundleCreate(kCFAllocatorDefault, (__bridge CFURLRef)bundleURL); + + // Don't continue if no Spacemouse driver is installed on this machine + if (spaceBundle == NULL) { + return; + } + + installConnexionHandlers = (InstallConnexionHandlersProc) + CFBundleGetFunctionPointerForName(spaceBundle, + CFSTR("InstallConnexionHandlers")); + + cleanupConnexionHandlers = (CleanupConnexionHandlersProc) + CFBundleGetFunctionPointerForName(spaceBundle, + CFSTR("CleanupConnexionHandlers")); + + registerConnexionClient = (RegisterConnexionClientProc) + CFBundleGetFunctionPointerForName(spaceBundle, + CFSTR("RegisterConnexionClient")); + + unregisterConnexionClient = (UnregisterConnexionClientProc) + CFBundleGetFunctionPointerForName(spaceBundle, + CFSTR("UnregisterConnexionClient")); + + // Only continue if all required symbols have been loaded + if ((installConnexionHandlers == NULL) || (cleanupConnexionHandlers == NULL) + || (registerConnexionClient == NULL) || (unregisterConnexionClient == NULL)) { + CFRelease(spaceBundle); + spaceBundle = NULL; + return; + } + + installConnexionHandlers(&connexionMessage, &connexionAdded, &connexionRemoved); + connexionClient = registerConnexionClient(connexionSignature, connexionName, + kConnexionClientModeTakeOver, kConnexionMaskButtons | kConnexionMaskAxis); + + // Monitor modifier flags to detect Shift button state changes + [NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyDownMask | NSFlagsChangedMask) + handler:^(NSEvent *event) { + if (event.modifierFlags & NSShiftKeyMask) { + connexionShiftIsDown = YES; + } + return event; + }]; + + [NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyUpMask | NSFlagsChangedMask) + handler:^(NSEvent *event) { + if (!(event.modifierFlags & NSShiftKeyMask)) { + connexionShiftIsDown = NO; + } + return event; + }]; +} + +static void connexionClose() { + if (spaceBundle == NULL) { + return; + } + + unregisterConnexionClient(connexionClient); + cleanupConnexionHandlers(); + + CFRelease(spaceBundle); +} + int main(int argc, const char *argv[]) { [NSApplication sharedApplication]; ApplicationDelegate *delegate = [[ApplicationDelegate alloc] init]; @@ -1182,11 +1337,15 @@ int main(int argc, const char *argv[]) { [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:nil topLevelObjects:nil]; SolveSpace::InitMainMenu([NSApp mainMenu]); + connexionInit(); SolveSpace::SS.Init(); [GW makeKeyAndOrderFront:nil]; - [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; + connexionClose(); + SolveSpace::SK.Clear(); + SolveSpace::SS.Clear(); + return 0; } diff --git a/src/confscreen.cpp b/src/confscreen.cpp index e518e1bd5..a7ad67835 100644 --- a/src/confscreen.cpp +++ b/src/confscreen.cpp @@ -453,6 +453,7 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) { } else { Error("Bad format: specify interval in integral minutes"); } + break; } default: return false; diff --git a/src/constraint.cpp b/src/constraint.cpp index 613702190..e5aae1b01 100644 --- a/src/constraint.cpp +++ b/src/constraint.cpp @@ -370,16 +370,21 @@ void Constraint::MenuConstrain(int id) { ((gs.workplanes == 1 && gs.n == 3) || (gs.n == 2))) { - c.entityA = gs.entity[0]; + if(gs.entities > 0) + c.entityA = gs.entity[0]; c.ptA = gs.point[0]; c.ptB = gs.point[1]; } else if(gs.lineSegments == 1 && ((gs.workplanes == 1 && gs.n == 2) || (gs.n == 1))) { - int i = SK.GetEntity(gs.entity[0])->IsWorkplane() ? 1 : 0; - Entity *line = SK.GetEntity(gs.entity[i]); - c.entityA = gs.entity[1-i]; + Entity *line; + if(SK.GetEntity(gs.entity[0])->IsWorkplane()) { + line = SK.GetEntity(gs.entity[1]); + c.entityA = gs.entity[0]; + } else { + line = SK.GetEntity(gs.entity[0]); + } c.ptA = line->point[0]; c.ptB = line->point[1]; } else if(SS.GW.LockedInWorkplane() diff --git a/src/draw.cpp b/src/draw.cpp index 597f9d817..64f10ca07 100644 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -156,6 +156,13 @@ void GraphicsWindow::MakeSelected(hEntity he) { stog.entity = he; MakeSelected(&stog); } + +void GraphicsWindow::MakeSelected(hConstraint hc) { + Selection stog = {}; + stog.constraint = hc; + MakeSelected(&stog); +} + void GraphicsWindow::MakeSelected(Selection *stog) { if(stog->IsEmpty()) return; if(IsSelected(stog)) return; @@ -242,7 +249,7 @@ void GraphicsWindow::SelectByMarquee(void) { void GraphicsWindow::GroupSelection(void) { gs = {}; int i; - for(i = 0; i < selection.n && i < MAX_SELECTED; i++) { + for(i = 0; i < selection.n; i++) { Selection *s = &(selection.elem[i]); if(s->entity.v) { (gs.n)++; @@ -253,27 +260,33 @@ void GraphicsWindow::GroupSelection(void) { // A list of points, and a list of all entities that aren't points. if(e->IsPoint()) { - gs.point[(gs.points)++] = s->entity; + gs.points++; + gs.point.push_back(s->entity); } else { - gs.entity[(gs.entities)++] = s->entity; + gs.entities++; + gs.entity.push_back(s->entity); } // And an auxiliary list of normals, including normals from // workplanes. if(e->IsNormal()) { - gs.anyNormal[(gs.anyNormals)++] = s->entity; + gs.anyNormals++; + gs.anyNormal.push_back(s->entity); } else if(e->IsWorkplane()) { - gs.anyNormal[(gs.anyNormals)++] = e->Normal()->h; + gs.anyNormals++; + gs.anyNormal.push_back(e->Normal()->h); } // And of vectors (i.e., stuff with a direction to constrain) if(e->HasVector()) { - gs.vector[(gs.vectors)++] = s->entity; + gs.vectors++; + gs.vector.push_back(s->entity); } // Faces (which are special, associated/drawn with triangles) if(e->IsFace()) { - gs.face[(gs.faces)++] = s->entity; + gs.faces++; + gs.face.push_back(s->entity); } if(e->HasEndpoints()) { @@ -296,7 +309,8 @@ void GraphicsWindow::GroupSelection(void) { } } if(s->constraint.v) { - gs.constraint[(gs.constraints)++] = s->constraint; + gs.constraints++; + gs.constraint.push_back(s->constraint); Constraint *c = SK.GetConstraint(s->constraint); if(c->IsStylable()) gs.stylables++; if(c->HasLabel()) gs.constraintLabels++; diff --git a/src/drawentity.cpp b/src/drawentity.cpp index 9efe7dcc6..39bc085e2 100644 --- a/src/drawentity.cpp +++ b/src/drawentity.cpp @@ -661,8 +661,8 @@ void Entity::DrawOrGetDistance(void) { } if(!h.isFromRequest()) { - mm = mm.Plus(v.ScaledBy(60/SS.GW.scale)); - mm2 = mm2.Plus(u.ScaledBy(60/SS.GW.scale)); + mm = mm.Plus(v.ScaledBy(70/SS.GW.scale)); + mm2 = mm2.Plus(u.ScaledBy(70/SS.GW.scale)); LineDrawOrGetDistance(mm2, mm); } LineDrawOrGetDistance(pp, pm); @@ -676,7 +676,9 @@ void Entity::DrawOrGetDistance(void) { std::string str = DescriptionString().substr(5); double th = Style::DefaultTextHeight(); if(dogd.drawing) { - ssglWriteText(str, th, mm2, u, v, NULL, NULL); + Vector o = mm2.Plus(u.ScaledBy(3/SS.GW.scale)).Plus( + v.ScaledBy(3/SS.GW.scale)); + ssglWriteText(str, th, o, u, v, NULL, NULL); } else { Vector pos = mm2.Plus(u.ScaledBy(ssglStrWidth(str, th)/2)).Plus( v.ScaledBy(ssglStrCapHeight(th)/2)); diff --git a/src/export.cpp b/src/export.cpp index f623edbb3..857ff6067 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -859,6 +859,8 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const std::string &filename,