From 651a0b86a7282549d42a8ba01984ae1471aa5ee1 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Wed, 7 Dec 2022 22:25:41 +0000 Subject: [PATCH] Import solvespace_3.1+ds1-3.debian.tar.xz [dgit import tarball solvespace 3.1+ds1-3 solvespace_3.1+ds1-3.debian.tar.xz] --- .gitlab-ci.yml | 6 + changelog | 197 ++ control | 71 + copyright | 267 ++ docs | 3 + libslvs1-dev.install | 2 + libslvs1.install | 1 + missing_sources/res/threejs/hammer-2.0.8.js | 2643 +++++++++++++++++++ patches/01_hardcode_git_hash.patch | 29 + patches/02_add_debian_pkg_version.patch | 22 + patches/03_use_system_threejs.patch | 44 + patches/04_use_system_unifont.patch | 35 + patches/series | 4 + rules | 36 + solvespace-cli.1 | 96 + solvespace.1 | 28 + solvespace.install | 3 + solvespace.links | 2 + solvespace.lintian-overrides | 3 + solvespace.manpages | 3 + solvespace.sharedmimeinfo | 8 + source/format | 1 + source/options | 5 + tests/common | 14 + tests/control | 8 + tests/htmlmesh | 15 + tests/stlmesh | 15 + tests/surfaces | 14 + tests/thumbnail | 16 + tests/view | 14 + tests/wireframe | 14 + upstream/metadata | 4 + watch | 8 + 33 files changed, 3631 insertions(+) create mode 100644 .gitlab-ci.yml create mode 100644 changelog create mode 100644 control create mode 100644 copyright create mode 100644 docs create mode 100644 libslvs1-dev.install create mode 100644 libslvs1.install create mode 100644 missing_sources/res/threejs/hammer-2.0.8.js create mode 100644 patches/01_hardcode_git_hash.patch create mode 100644 patches/02_add_debian_pkg_version.patch create mode 100644 patches/03_use_system_threejs.patch create mode 100644 patches/04_use_system_unifont.patch create mode 100644 patches/series create mode 100755 rules create mode 100644 solvespace-cli.1 create mode 100644 solvespace.1 create mode 100644 solvespace.install create mode 100644 solvespace.links create mode 100644 solvespace.lintian-overrides create mode 100644 solvespace.manpages create mode 100644 solvespace.sharedmimeinfo create mode 100644 source/format create mode 100644 source/options create mode 100644 tests/common create mode 100644 tests/control create mode 100755 tests/htmlmesh create mode 100755 tests/stlmesh create mode 100755 tests/surfaces create mode 100755 tests/thumbnail create mode 100755 tests/view create mode 100755 tests/wireframe create mode 100644 upstream/metadata create mode 100644 watch diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..b9b8b88 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,6 @@ +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml + +reprotest: + allow_failure: true \ No newline at end of file diff --git a/changelog b/changelog new file mode 100644 index 0000000..55ea8ce --- /dev/null +++ b/changelog @@ -0,0 +1,197 @@ +solvespace (3.1+ds1-3) unstable; urgency=medium + + * Team upload. + * Restore architectures, and just exclude s390x from affected tests. + Thanks to Graham Inggs. Closes: #1025311 + + -- Ryan Pavlik Wed, 07 Dec 2022 16:25:41 -0600 + +solvespace (3.1+ds1-2) unstable; urgency=medium + + * Team upload. + * Drop s390x architecture due to test failures. Closes: #1013163 + * Bump Standards-Version to 4.6.1. No changes required. + * d/copyright: Update + * Update lintian overrides. + + -- Ryan Pavlik Mon, 19 Sep 2022 12:49:06 -0500 + +solvespace (3.1+ds1-1) unstable; urgency=medium + + * Team upload. + * New upstream version 3.1+ds1 + * Rediff patches. + Drop 05_eigen_dependency_fix.patch: Applied upstream. + Drop 06_desktop_file_exec.patch: Applied upstream. + + -- Ryan Pavlik Mon, 11 Jul 2022 08:55:26 -0500 + +solvespace (3.1~rc1+ds1-1) unstable; urgency=medium + + * New upstream version 3.1~rc1+ds1. Closes: #983952 + * d/watch: Update to get new pattern for tarballs with submodules + * d/control: + - Add Build-Depends. + - Remove libjs-three and unifont from Build-Depends, only + needed at runtime for the GUI + * d/copyright: Exclude vendored files available in Debian, binaries, + minified Javascript, prebuilt docs + * d/solvespace.lintian-overrides: Add overrides for false positives + * d/get_orig.sh: Remove, no longer needed, uscan works now. + * d/patches: + - Drop 10_mimalloc_restrict_cpu_yield.patch: applied upstream. + - Drop 11_update_js_three_r111.patch: applied upstream. + - Drop 12_Remove-march-native-from-mimalloc-build.patch: applied upstream. + - Revise 01_RemoveGitHash.patch into 01_hardcode_git_hash.patch: Hash + needed to create commit link in app now. + - Add 05_eigen_dependency_fix.patch: Fix test suite build. + - Add 06_desktop_file_exec.patch: Fix desktop file lintian warning. + + -- Ryan Pavlik Thu, 19 May 2022 16:05:37 -0500 + +solvespace (3.0.rc2+repack1-3) unstable; urgency=medium + + * Add 12_Remove-march-native-from-mimalloc-build.patch: + fix buildd-discovered issue. + * Update patch metadata. + + -- Ryan Pavlik Thu, 11 Feb 2021 15:06:33 -0600 + +solvespace (3.0.rc2+repack1-2) unstable; urgency=medium + + * Upload into unstable + + -- Anton Gladky Sat, 06 Feb 2021 20:04:57 +0100 + +solvespace (3.0.rc2+repack1-2~exp1) experimental; urgency=medium + + * Team upload. + [ Ryan Pavlik ] + * Enable LTO and OpenMP in build system + + [ Michael R. Crusoe ] + * Remove erroneously added debian/salsa-ci.yml. + + -- Michael R. Crusoe Sat, 23 Jan 2021 20:31:05 +0100 + +solvespace (3.0.rc2+repack1-1) unstable; urgency=medium + + * Team upload. + + [ Ryan Pavlik ] + * New upstream version 3.0.rc2+repack1 + * Adjust get_orig.sh script for RC2 + * d/rules: Specify package version for CMake. + * Drop 20_use_system_flatbuffers: Upstream dep removed. + * Add 02_add_debian_pkg_version.patch to provide better + version ID to upstream + * Add 03_use_system_threejs.patch, update d/control to use + system-provided three.js + * Add 04_use_system_unifont.patch, update d/control to use + system unifont + * Add 10_mimalloc_restrict_cpu_yield.patch to fix mimalloc + armel build. + * Add 11_update_js_three_r111.patch to support three.js r111 + as found in unstable, instead of old r76 bundled in tree. + * d/control + - Fix warning about substitution variable + - Update description to cover new operations + - Update version in Build-Depends for CMake + - Remove Build-Depends on libflatbuffers-dev. + * Add missing_sources for hammer js + * Update copyright file + * Package more docs + * Add manpage for solvespace-cli from notesalexp repo. + * Update solvespace manpage + * Ensure build flags are exported and used + * Add autopkgtests + + [ Michael R. Crusoe ] + * Do not parse d/changelog (routine-update) + * Add salsa-ci file (routine-update) + * debian/upstream/metadata: mention upstream's GitHub repository + * debian/patches/03_use_system_threejs.patch: refreshed + * debian/patches/10_mimalloc_restrict_cpu_yield.patch: enhanced with better + atomic yield for SSE2 (if available) and better/added ops for arm64, + armel, and ppc64{el,}/powerpc. Closes: #980169 + * Run the build-time tests as part of the build on amd64. + + -- Michael R. Crusoe Sat, 23 Jan 2021 20:15:11 +0100 + +solvespace (3.0.rc1+repack1-4) unstable; urgency=medium + + * [3fa5dd1] Remove arm-patch + + -- Anton Gladky Fri, 15 Jan 2021 15:40:02 +0100 + +solvespace (3.0.rc1+repack1-3) unstable; urgency=medium + + * [fa2ba63] Use CXX for mimalloc compilation + + -- Anton Gladky Thu, 14 Jan 2021 23:41:14 +0100 + +solvespace (3.0.rc1+repack1-2) unstable; urgency=medium + + * [7192813] Update d/copyright + * [93f958e] Fix compilation on armel + + -- Anton Gladky Thu, 14 Jan 2021 19:41:26 +0100 + +solvespace (3.0.rc1+repack1-1) unstable; urgency=medium + + * [2c974c1] New upstream version 3.0.rc1+repack1 + * [d29ee68] Update get_orig script + * [73cbc23] Refresh patches + * [d8e0c6c] Use gtk3. (Closes: #967751) + * [09453c9] Update watch file format version to 4. + * [70475f7] Set Standards-Version to 4.5.1 + + -- Anton Gladky Tue, 12 Jan 2021 23:27:41 +0100 + +solvespace (2.3+repack1-4) unstable; urgency=medium + + * [f5f8b5c] Add link to the fixed by upstream issue + * [4ac4b71] Use secure URI in Homepage field. + * [ef3f5da] Bump debhelper from old 10 to 13. + * [047d9c4] Set debhelper-compat version in Build-Depends. + * [8b28a26] Set upstream metadata fields: Bug-Database, Bug-Submit. + * [fba85d0] Update Vcs-* headers from URL redirect. + * [ab740f9] Use canonical URL in Vcs-Git. + * [84a98ae] Replace libglu-dev by libglu1-mesa-dev in BD + * [fdf3c0d] Set Standards-version to 4.5.0. No changes + * [cefcb01] Set Rules-Requires-Root: no + * [9869a0d] Add .gitlab-ci.yml + * [53ab556] Install usr/share/pixmaps + + -- Anton Gladky Mon, 01 Jun 2020 22:17:17 +0200 + +solvespace (2.3+repack1-3) unstable; urgency=medium + + * [6d84f29] Set minimal cmake version to 3.1.0. + * [be690c9] Fix FTBFS with glibc 2.25. (Closes: #882167) + * [6c8697c] Set Standards-Version: 4.1.1 + * [2c3d9bd] Set compat level 10 + * [fb232b5] Set maximal hardening options + + -- Anton Gladky Wed, 22 Nov 2017 09:54:12 +0100 + +solvespace (2.3+repack1-2) unstable; urgency=medium + + * [0d4dc2b] Add missing dependency on libslvs1. (Closes: #856937) + + -- Anton Gladky Mon, 06 Mar 2017 20:59:20 +0100 + +solvespace (2.3+repack1-1) unstable; urgency=medium + + * [a7825d4] Add d/watch. + * [15facd8] Update get_orig.sh script. + * [4bcf775] New upstream version 2.3+repack1 + * [5bfcd9a] Refresh patch. + + -- Anton Gladky Sat, 31 Dec 2016 09:54:59 +0100 + +solvespace (2.1+repack2-1) unstable; urgency=medium + + * Initial Release. (Closes: #797997) + + -- Anton Gladky Mon, 15 Aug 2016 22:31:44 +0200 diff --git a/control b/control new file mode 100644 index 0000000..58bf06b --- /dev/null +++ b/control @@ -0,0 +1,71 @@ +Source: solvespace +Maintainer: Debian Science Maintainers +Uploaders: whitequark , + Anton Gladky +Section: graphics +Priority: optional +Build-Depends: cmake (>= 3.9), + debhelper-compat (= 13), + libeigen3-dev, + libfontconfig1-dev, + libfreetype-dev, + libgl-dev, + libglew-dev, + libglu1-mesa-dev, + libgtkmm-3.0-dev, + libjson-c-dev, + libpangomm-1.4-dev, + libpng-dev, + libspnav-dev, + zlib1g-dev +Standards-Version: 4.6.1 +Vcs-Browser: https://salsa.debian.org/science-team/solvespace +Vcs-Git: https://salsa.debian.org/science-team/solvespace.git +Homepage: https://solvespace.com +Rules-Requires-Root: no + +Package: solvespace +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, + ${shlibs:Depends}, + libjs-three, + unifont +Description: Parametric 2d/3d CAD + SolveSpace is a parametric 2d/3d CAD program. Applications include: + . + * modeling 3d parts — draw with extrudes, revolves, helix creation, + and Boolean (union / difference / intersection) 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: libslvs1 +Architecture: any +Multi-Arch: same +Section: libs +Depends: ${misc:Depends}, + ${shlibs: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 +Architecture: any +Multi-Arch: same +Section: libdevel +Depends: ${misc:Depends}, + libslvs1 (= ${binary:Version}) +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. diff --git a/copyright b/copyright new file mode 100644 index 0000000..b9727b2 --- /dev/null +++ b/copyright @@ -0,0 +1,267 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: solvespace +Source: https://github.com/solvespace/solvespace +Comment: Excluding vendored third-party libs available in Debian, + minified javascript, vendored unifot, Windows-only binaries, and + prebuilt documentation +Files-Excluded: + extlib/angle + extlib/cairo + extlib/eigen + extlib/freetype + extlib/libpng + extlib/mimalloc/bin + extlib/mimalloc/docs + extlib/pixman + extlib/si + extlib/zlib + res/fonts/unifont.hex.gz + res/threejs/three-* + +Files: * +Copyright: 2008-2022, Jonathan Westhues and other authors + 2015-2020, whitequark + 2015, 2016, Aleksey Egorov +License: GPL-3.0+ + +Files: cmake/* +Copyright: 2008-2020, Jonathan Westhues and other authors +License: GPL-3.0+ + +Files: debian/* +Copyright: 2021-2022, Ryan Pavlik + 2016, 2017, 2020, 2021, Anton Gladky + 2015, 2016, whitequark +License: GPL-3.0+ + +Files: debian/solvespace-cli.1 +Copyright: 2016 Alexander Pozdnyakov +License: GPL-3.0+ + +Files: debian/missing_sources/res/threejs/hammer-2.0.8.js + res/threejs/hammer-2.0.8.js.gz +Copyright: 2016, Jorik Tangelder +License: Expat + +Files: extlib/libdxfrw/* +Copyright: 2011-2015, José F. Soriano (Rallaz) +License: GPL-2.0+ + +Files: extlib/mimalloc/* +Copyright: 2018-2021, Microsoft Research + 2019, Daan Leijen +License: Expat + +Files: src/importidf.cpp +Copyright: 2020, Paul Kahler. +License: GPL-3.0+ + +Files: src/polyline.cpp +Copyright: 2016, M-Labs Ltd +License: GPL-3.0+ + +Files: src/ttf.cpp + src/ttf.h +Copyright: 2016, whitequark, Peter Barfuss. +License: GPL-3.0+ + +Files: res/fonts/unicode.lff.gz +Copyright: 2011-2012, José F. Soriano + 2011, Eugene Osintsev + 2002, Yoshimune Kobayashi +License: GPL-2.0+ +Comment: From LibreCAD, referenced explicitly by path. + +Files: test/Gentium-R.ttf +Copyright: 2003-2011, SIL International +License: OFL-1.1-RFN +Comment: Reserved Font Names "Gentium" and "SIL". Used for test cases. + +Files: res/fonts/BitstreamVeraSans-Roman-builtin.ttf +Copyright: 2003, Bitstream, Inc. +License: other + Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a + trademark of Bitstream, Inc. + . + Permission is hereby granted, free of charge, to any person obtaining a copy of + the fonts accompanying this license (“Fonts”) and associated documentation files + (the “Font Software”), to reproduce and distribute the Font Software, including + without limitation the rights to use, copy, merge, publish, distribute, and/or + sell copies of the Font Software, and to permit persons to whom the Font + Software is furnished to do so, subject to the following conditions: + . + The above copyright and trademark notices and this permission notice shall be + included in all copies of one or more of the Font Software typefaces. + . + The Font Software may be modified, altered, or added to, and in particular the + designs of glyphs or characters in the Fonts may be modified and additional + glyphs or characters may be added to the Fonts, only if the fonts are renamed to + names not containing either the words “Bitstream” or the word “Vera”. + . + This License becomes null and void to the extent applicable to Fonts or Font + Software that has been modified and is distributed under the “Bitstream Vera” + names. + . + The Font Software may be sold as part of a larger software package but no copy + of one or more of the Font Software typefaces may be sold by itself. + . + THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR + OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, + INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR + FROM OTHER DEALINGS IN THE FONT SOFTWARE. + . + Except as contained in this notice, the names of GNOME, the GNOME Foundation, + and Bitstream Inc., shall not be used in advertising or otherwise to promote the + sale, use or other dealings in this Font Software without prior written + authorization from the GNOME Foundation or Bitstream Inc., respectively. For + further information, contact: fonts at gnome dot org. + +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +License: GPL-2.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 2 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 2 can be found in "/usr/share/common-licenses/GPL-2". + +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". + +License: OFL-1.1-RFN + This Font Software is licensed under the SIL Open Font License, Version 1.1. + This license is copied below, and is also available with a FAQ at: + http://scripts.sil.org/OFL + . + . + ----------------------------------------------------------- + SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + ----------------------------------------------------------- + . + PREAMBLE + The goals of the Open Font License (OFL) are to stimulate worldwide + development of collaborative font projects, to support the font creation + efforts of academic and linguistic communities, and to provide a free and + open framework in which fonts may be shared and improved in partnership + with others. + . + The OFL allows the licensed fonts to be used, studied, modified and + redistributed freely as long as they are not sold by themselves. The + fonts, including any derivative works, can be bundled, embedded, + redistributed and/or sold with any software provided that any reserved + names are not used by derivative works. The fonts and derivatives, + however, cannot be released under any other type of license. The + requirement for fonts to remain under this license does not apply + to any document created using the fonts or their derivatives. + . + DEFINITIONS + "Font Software" refers to the set of files released by the Copyright + Holder(s) under this license and clearly marked as such. This may + include source files, build scripts and documentation. + . + "Reserved Font Name" refers to any names specified as such after the + copyright statement(s). + . + "Original Version" refers to the collection of Font Software components as + distributed by the Copyright Holder(s). + . + "Modified Version" refers to any derivative made by adding to, deleting, + or substituting -- in part or in whole -- any of the components of the + Original Version, by changing formats or by porting the Font Software to a + new environment. + . + "Author" refers to any designer, engineer, programmer, technical + writer or other person who contributed to the Font Software. + . + PERMISSION & CONDITIONS + Permission is hereby granted, free of charge, to any person obtaining + a copy of the Font Software, to use, study, copy, merge, embed, modify, + redistribute, and sell modified and unmodified copies of the Font + Software, subject to the following conditions: + . + 1) Neither the Font Software nor any of its individual components, + in Original or Modified Versions, may be sold by itself. + . + 2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + . + 3) No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the corresponding + Copyright Holder. This restriction only applies to the primary font name as + presented to the users. + . + 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + . + 5) The Font Software, modified or unmodified, in part or in whole, + must be distributed entirely under this license, and must not be + distributed under any other license. The requirement for fonts to + remain under this license does not apply to any document created + using the Font Software. + . + TERMINATION + This license becomes null and void if any of the above conditions are + not met. + . + DISCLAIMER + THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE + COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL + DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM + OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs b/docs new file mode 100644 index 0000000..e48692b --- /dev/null +++ b/docs @@ -0,0 +1,3 @@ +README.md +CHANGELOG.md +THIRD_PARTIES.txt diff --git a/libslvs1-dev.install b/libslvs1-dev.install new file mode 100644 index 0000000..8de0fcd --- /dev/null +++ b/libslvs1-dev.install @@ -0,0 +1,2 @@ +usr/include/slvs.h +usr/lib/*/libslvs.so diff --git a/libslvs1.install b/libslvs1.install new file mode 100644 index 0000000..ffa6d6e --- /dev/null +++ b/libslvs1.install @@ -0,0 +1 @@ +usr/lib/*/libslvs.so.* diff --git a/missing_sources/res/threejs/hammer-2.0.8.js b/missing_sources/res/threejs/hammer-2.0.8.js new file mode 100644 index 0000000..00d2965 --- /dev/null +++ b/missing_sources/res/threejs/hammer-2.0.8.js @@ -0,0 +1,2643 @@ +/*! Hammer.JS - v2.0.7 - 2016-04-22 + * http://hammerjs.github.io/ + * + * Copyright (c) 2016 Jorik Tangelder; + * Licensed under the MIT license */ +(function(window, document, exportName, undefined) { + 'use strict'; + +var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o']; +var TEST_ELEMENT = document.createElement('div'); + +var TYPE_FUNCTION = 'function'; + +var round = Math.round; +var abs = Math.abs; +var now = Date.now; + +/** + * set a timeout with a given scope + * @param {Function} fn + * @param {Number} timeout + * @param {Object} context + * @returns {number} + */ +function setTimeoutContext(fn, timeout, context) { + return setTimeout(bindFn(fn, context), timeout); +} + +/** + * if the argument is an array, we want to execute the fn on each entry + * if it aint an array we don't want to do a thing. + * this is used by all the methods that accept a single and array argument. + * @param {*|Array} arg + * @param {String} fn + * @param {Object} [context] + * @returns {Boolean} + */ +function invokeArrayArg(arg, fn, context) { + if (Array.isArray(arg)) { + each(arg, context[fn], context); + return true; + } + return false; +} + +/** + * walk objects and arrays + * @param {Object} obj + * @param {Function} iterator + * @param {Object} context + */ +function each(obj, iterator, context) { + var i; + + if (!obj) { + return; + } + + if (obj.forEach) { + obj.forEach(iterator, context); + } else if (obj.length !== undefined) { + i = 0; + while (i < obj.length) { + iterator.call(context, obj[i], i, obj); + i++; + } + } else { + for (i in obj) { + obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj); + } + } +} + +/** + * wrap a method with a deprecation warning and stack trace + * @param {Function} method + * @param {String} name + * @param {String} message + * @returns {Function} A new function wrapping the supplied method. + */ +function deprecate(method, name, message) { + var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n'; + return function() { + var e = new Error('get-stack-trace'); + var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '') + .replace(/^\s+at\s+/gm, '') + .replace(/^Object.\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace'; + + var log = window.console && (window.console.warn || window.console.log); + if (log) { + log.call(window.console, deprecationMessage, stack); + } + return method.apply(this, arguments); + }; +} + +/** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} target + * @param {...Object} objects_to_assign + * @returns {Object} target + */ +var assign; +if (typeof Object.assign !== 'function') { + assign = function assign(target) { + if (target === undefined || target === null) { + throw new TypeError('Cannot convert undefined or null to object'); + } + + var output = Object(target); + for (var index = 1; index < arguments.length; index++) { + var source = arguments[index]; + if (source !== undefined && source !== null) { + for (var nextKey in source) { + if (source.hasOwnProperty(nextKey)) { + output[nextKey] = source[nextKey]; + } + } + } + } + return output; + }; +} else { + assign = Object.assign; +} + +/** + * extend object. + * means that properties in dest will be overwritten by the ones in src. + * @param {Object} dest + * @param {Object} src + * @param {Boolean} [merge=false] + * @returns {Object} dest + */ +var extend = deprecate(function extend(dest, src, merge) { + var keys = Object.keys(src); + var i = 0; + while (i < keys.length) { + if (!merge || (merge && dest[keys[i]] === undefined)) { + dest[keys[i]] = src[keys[i]]; + } + i++; + } + return dest; +}, 'extend', 'Use `assign`.'); + +/** + * merge the values from src in the dest. + * means that properties that exist in dest will not be overwritten by src + * @param {Object} dest + * @param {Object} src + * @returns {Object} dest + */ +var merge = deprecate(function merge(dest, src) { + return extend(dest, src, true); +}, 'merge', 'Use `assign`.'); + +/** + * simple class inheritance + * @param {Function} child + * @param {Function} base + * @param {Object} [properties] + */ +function inherit(child, base, properties) { + var baseP = base.prototype, + childP; + + childP = child.prototype = Object.create(baseP); + childP.constructor = child; + childP._super = baseP; + + if (properties) { + assign(childP, properties); + } +} + +/** + * simple function bind + * @param {Function} fn + * @param {Object} context + * @returns {Function} + */ +function bindFn(fn, context) { + return function boundFn() { + return fn.apply(context, arguments); + }; +} + +/** + * let a boolean value also be a function that must return a boolean + * this first item in args will be used as the context + * @param {Boolean|Function} val + * @param {Array} [args] + * @returns {Boolean} + */ +function boolOrFn(val, args) { + if (typeof val == TYPE_FUNCTION) { + return val.apply(args ? args[0] || undefined : undefined, args); + } + return val; +} + +/** + * use the val2 when val1 is undefined + * @param {*} val1 + * @param {*} val2 + * @returns {*} + */ +function ifUndefined(val1, val2) { + return (val1 === undefined) ? val2 : val1; +} + +/** + * addEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ +function addEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.addEventListener(type, handler, false); + }); +} + +/** + * removeEventListener with multiple events at once + * @param {EventTarget} target + * @param {String} types + * @param {Function} handler + */ +function removeEventListeners(target, types, handler) { + each(splitStr(types), function(type) { + target.removeEventListener(type, handler, false); + }); +} + +/** + * find if a node is in the given parent + * @method hasParent + * @param {HTMLElement} node + * @param {HTMLElement} parent + * @return {Boolean} found + */ +function hasParent(node, parent) { + while (node) { + if (node == parent) { + return true; + } + node = node.parentNode; + } + return false; +} + +/** + * small indexOf wrapper + * @param {String} str + * @param {String} find + * @returns {Boolean} found + */ +function inStr(str, find) { + return str.indexOf(find) > -1; +} + +/** + * split string on whitespace + * @param {String} str + * @returns {Array} words + */ +function splitStr(str) { + return str.trim().split(/\s+/g); +} + +/** + * find if a array contains the object using indexOf or a simple polyFill + * @param {Array} src + * @param {String} find + * @param {String} [findByKey] + * @return {Boolean|Number} false when not found, or the index + */ +function inArray(src, find, findByKey) { + if (src.indexOf && !findByKey) { + return src.indexOf(find); + } else { + var i = 0; + while (i < src.length) { + if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) { + return i; + } + i++; + } + return -1; + } +} + +/** + * convert array-like objects to real arrays + * @param {Object} obj + * @returns {Array} + */ +function toArray(obj) { + return Array.prototype.slice.call(obj, 0); +} + +/** + * unique array with objects based on a key (like 'id') or just by the array's value + * @param {Array} src [{id:1},{id:2},{id:1}] + * @param {String} [key] + * @param {Boolean} [sort=False] + * @returns {Array} [{id:1},{id:2}] + */ +function uniqueArray(src, key, sort) { + var results = []; + var values = []; + var i = 0; + + while (i < src.length) { + var val = key ? src[i][key] : src[i]; + if (inArray(values, val) < 0) { + results.push(src[i]); + } + values[i] = val; + i++; + } + + if (sort) { + if (!key) { + results = results.sort(); + } else { + results = results.sort(function sortUniqueArray(a, b) { + return a[key] > b[key]; + }); + } + } + + return results; +} + +/** + * get the prefixed property + * @param {Object} obj + * @param {String} property + * @returns {String|Undefined} prefixed + */ +function prefixed(obj, property) { + var prefix, prop; + var camelProp = property[0].toUpperCase() + property.slice(1); + + var i = 0; + while (i < VENDOR_PREFIXES.length) { + prefix = VENDOR_PREFIXES[i]; + prop = (prefix) ? prefix + camelProp : property; + + if (prop in obj) { + return prop; + } + i++; + } + return undefined; +} + +/** + * get a unique id + * @returns {number} uniqueId + */ +var _uniqueId = 1; +function uniqueId() { + return _uniqueId++; +} + +/** + * get the window object of an element + * @param {HTMLElement} element + * @returns {DocumentView|Window} + */ +function getWindowForElement(element) { + var doc = element.ownerDocument || element; + return (doc.defaultView || doc.parentWindow || window); +} + +var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i; + +var SUPPORT_TOUCH = ('ontouchstart' in window); +var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined; +var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent); + +var INPUT_TYPE_TOUCH = 'touch'; +var INPUT_TYPE_PEN = 'pen'; +var INPUT_TYPE_MOUSE = 'mouse'; +var INPUT_TYPE_KINECT = 'kinect'; + +var COMPUTE_INTERVAL = 25; + +var INPUT_START = 1; +var INPUT_MOVE = 2; +var INPUT_END = 4; +var INPUT_CANCEL = 8; + +var DIRECTION_NONE = 1; +var DIRECTION_LEFT = 2; +var DIRECTION_RIGHT = 4; +var DIRECTION_UP = 8; +var DIRECTION_DOWN = 16; + +var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT; +var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN; +var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL; + +var PROPS_XY = ['x', 'y']; +var PROPS_CLIENT_XY = ['clientX', 'clientY']; + +/** + * create new input type manager + * @param {Manager} manager + * @param {Function} callback + * @returns {Input} + * @constructor + */ +function Input(manager, callback) { + var self = this; + this.manager = manager; + this.callback = callback; + this.element = manager.element; + this.target = manager.options.inputTarget; + + // smaller wrapper around the handler, for the scope and the enabled state of the manager, + // so when disabled the input events are completely bypassed. + this.domHandler = function(ev) { + if (boolOrFn(manager.options.enable, [manager])) { + self.handler(ev); + } + }; + + this.init(); + +} + +Input.prototype = { + /** + * should handle the inputEvent data and trigger the callback + * @virtual + */ + handler: function() { }, + + /** + * bind the events + */ + init: function() { + this.evEl && addEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + }, + + /** + * unbind the events + */ + destroy: function() { + this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler); + this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler); + this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); + } +}; + +/** + * create new input type manager + * called by the Manager constructor + * @param {Hammer} manager + * @returns {Input} + */ +function createInputInstance(manager) { + var Type; + var inputClass = manager.options.inputClass; + + if (inputClass) { + Type = inputClass; + } else if (SUPPORT_POINTER_EVENTS) { + Type = PointerEventInput; + } else if (SUPPORT_ONLY_TOUCH) { + Type = TouchInput; + } else if (!SUPPORT_TOUCH) { + Type = MouseInput; + } else { + Type = TouchMouseInput; + } + return new (Type)(manager, inputHandler); +} + +/** + * handle input events + * @param {Manager} manager + * @param {String} eventType + * @param {Object} input + */ +function inputHandler(manager, eventType, input) { + var pointersLen = input.pointers.length; + var changedPointersLen = input.changedPointers.length; + var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0)); + var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0)); + + input.isFirst = !!isFirst; + input.isFinal = !!isFinal; + + if (isFirst) { + manager.session = {}; + } + + // source event is the normalized value of the domEvents + // like 'touchstart, mouseup, pointerdown' + input.eventType = eventType; + + // compute scale, rotation etc + computeInputData(manager, input); + + // emit secret event + manager.emit('hammer.input', input); + + manager.recognize(input); + manager.session.prevInput = input; +} + +/** + * extend the data with some usable properties like scale, rotate, velocity etc + * @param {Object} manager + * @param {Object} input + */ +function computeInputData(manager, input) { + var session = manager.session; + var pointers = input.pointers; + var pointersLength = pointers.length; + + // store the first input to calculate the distance and direction + if (!session.firstInput) { + session.firstInput = simpleCloneInputData(input); + } + + // to compute scale and rotation we need to store the multiple touches + if (pointersLength > 1 && !session.firstMultiple) { + session.firstMultiple = simpleCloneInputData(input); + } else if (pointersLength === 1) { + session.firstMultiple = false; + } + + var firstInput = session.firstInput; + var firstMultiple = session.firstMultiple; + var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center; + + var center = input.center = getCenter(pointers); + input.timeStamp = now(); + input.deltaTime = input.timeStamp - firstInput.timeStamp; + + input.angle = getAngle(offsetCenter, center); + input.distance = getDistance(offsetCenter, center); + + computeDeltaXY(session, input); + input.offsetDirection = getDirection(input.deltaX, input.deltaY); + + var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY); + input.overallVelocityX = overallVelocity.x; + input.overallVelocityY = overallVelocity.y; + input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y; + + input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1; + input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0; + + input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length > + session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers); + + computeIntervalInputData(session, input); + + // find the correct target + var target = manager.element; + if (hasParent(input.srcEvent.target, target)) { + target = input.srcEvent.target; + } + input.target = target; +} + +function computeDeltaXY(session, input) { + var center = input.center; + var offset = session.offsetDelta || {}; + var prevDelta = session.prevDelta || {}; + var prevInput = session.prevInput || {}; + + if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) { + prevDelta = session.prevDelta = { + x: prevInput.deltaX || 0, + y: prevInput.deltaY || 0 + }; + + offset = session.offsetDelta = { + x: center.x, + y: center.y + }; + } + + input.deltaX = prevDelta.x + (center.x - offset.x); + input.deltaY = prevDelta.y + (center.y - offset.y); +} + +/** + * velocity is calculated every x ms + * @param {Object} session + * @param {Object} input + */ +function computeIntervalInputData(session, input) { + var last = session.lastInterval || input, + deltaTime = input.timeStamp - last.timeStamp, + velocity, velocityX, velocityY, direction; + + if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) { + var deltaX = input.deltaX - last.deltaX; + var deltaY = input.deltaY - last.deltaY; + + var v = getVelocity(deltaTime, deltaX, deltaY); + velocityX = v.x; + velocityY = v.y; + velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y; + direction = getDirection(deltaX, deltaY); + + session.lastInterval = input; + } else { + // use latest velocity info if it doesn't overtake a minimum period + velocity = last.velocity; + velocityX = last.velocityX; + velocityY = last.velocityY; + direction = last.direction; + } + + input.velocity = velocity; + input.velocityX = velocityX; + input.velocityY = velocityY; + input.direction = direction; +} + +/** + * create a simple clone from the input used for storage of firstInput and firstMultiple + * @param {Object} input + * @returns {Object} clonedInputData + */ +function simpleCloneInputData(input) { + // make a simple copy of the pointers because we will get a reference if we don't + // we only need clientXY for the calculations + var pointers = []; + var i = 0; + while (i < input.pointers.length) { + pointers[i] = { + clientX: round(input.pointers[i].clientX), + clientY: round(input.pointers[i].clientY) + }; + i++; + } + + return { + timeStamp: now(), + pointers: pointers, + center: getCenter(pointers), + deltaX: input.deltaX, + deltaY: input.deltaY + }; +} + +/** + * get the center of all the pointers + * @param {Array} pointers + * @return {Object} center contains `x` and `y` properties + */ +function getCenter(pointers) { + var pointersLength = pointers.length; + + // no need to loop when only one touch + if (pointersLength === 1) { + return { + x: round(pointers[0].clientX), + y: round(pointers[0].clientY) + }; + } + + var x = 0, y = 0, i = 0; + while (i < pointersLength) { + x += pointers[i].clientX; + y += pointers[i].clientY; + i++; + } + + return { + x: round(x / pointersLength), + y: round(y / pointersLength) + }; +} + +/** + * calculate the velocity between two points. unit is in px per ms. + * @param {Number} deltaTime + * @param {Number} x + * @param {Number} y + * @return {Object} velocity `x` and `y` + */ +function getVelocity(deltaTime, x, y) { + return { + x: x / deltaTime || 0, + y: y / deltaTime || 0 + }; +} + +/** + * get the direction between two points + * @param {Number} x + * @param {Number} y + * @return {Number} direction + */ +function getDirection(x, y) { + if (x === y) { + return DIRECTION_NONE; + } + + if (abs(x) >= abs(y)) { + return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return y < 0 ? DIRECTION_UP : DIRECTION_DOWN; +} + +/** + * calculate the absolute distance between two points + * @param {Object} p1 {x, y} + * @param {Object} p2 {x, y} + * @param {Array} [props] containing x and y keys + * @return {Number} distance + */ +function getDistance(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + + return Math.sqrt((x * x) + (y * y)); +} + +/** + * calculate the angle between two coordinates + * @param {Object} p1 + * @param {Object} p2 + * @param {Array} [props] containing x and y keys + * @return {Number} angle + */ +function getAngle(p1, p2, props) { + if (!props) { + props = PROPS_XY; + } + var x = p2[props[0]] - p1[props[0]], + y = p2[props[1]] - p1[props[1]]; + return Math.atan2(y, x) * 180 / Math.PI; +} + +/** + * calculate the rotation degrees between two pointersets + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} rotation + */ +function getRotation(start, end) { + return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY); +} + +/** + * calculate the scale factor between two pointersets + * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out + * @param {Array} start array of pointers + * @param {Array} end array of pointers + * @return {Number} scale + */ +function getScale(start, end) { + return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY); +} + +var MOUSE_INPUT_MAP = { + mousedown: INPUT_START, + mousemove: INPUT_MOVE, + mouseup: INPUT_END +}; + +var MOUSE_ELEMENT_EVENTS = 'mousedown'; +var MOUSE_WINDOW_EVENTS = 'mousemove mouseup'; + +/** + * Mouse events input + * @constructor + * @extends Input + */ +function MouseInput() { + this.evEl = MOUSE_ELEMENT_EVENTS; + this.evWin = MOUSE_WINDOW_EVENTS; + + this.pressed = false; // mousedown state + + Input.apply(this, arguments); +} + +inherit(MouseInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function MEhandler(ev) { + var eventType = MOUSE_INPUT_MAP[ev.type]; + + // on start we want to have the left mouse button down + if (eventType & INPUT_START && ev.button === 0) { + this.pressed = true; + } + + if (eventType & INPUT_MOVE && ev.which !== 1) { + eventType = INPUT_END; + } + + // mouse must be down + if (!this.pressed) { + return; + } + + if (eventType & INPUT_END) { + this.pressed = false; + } + + this.callback(this.manager, eventType, { + pointers: [ev], + changedPointers: [ev], + pointerType: INPUT_TYPE_MOUSE, + srcEvent: ev + }); + } +}); + +var POINTER_INPUT_MAP = { + pointerdown: INPUT_START, + pointermove: INPUT_MOVE, + pointerup: INPUT_END, + pointercancel: INPUT_CANCEL, + pointerout: INPUT_CANCEL +}; + +// in IE10 the pointer types is defined as an enum +var IE10_POINTER_TYPE_ENUM = { + 2: INPUT_TYPE_TOUCH, + 3: INPUT_TYPE_PEN, + 4: INPUT_TYPE_MOUSE, + 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816 +}; + +var POINTER_ELEMENT_EVENTS = 'pointerdown'; +var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; + +// IE10 has prefixed support, and case-sensitive +if (window.MSPointerEvent && !window.PointerEvent) { + POINTER_ELEMENT_EVENTS = 'MSPointerDown'; + POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel'; +} + +/** + * Pointer events input + * @constructor + * @extends Input + */ +function PointerEventInput() { + this.evEl = POINTER_ELEMENT_EVENTS; + this.evWin = POINTER_WINDOW_EVENTS; + + Input.apply(this, arguments); + + this.store = (this.manager.session.pointerEvents = []); +} + +inherit(PointerEventInput, Input, { + /** + * handle mouse events + * @param {Object} ev + */ + handler: function PEhandler(ev) { + var store = this.store; + var removePointer = false; + + var eventTypeNormalized = ev.type.toLowerCase().replace('ms', ''); + var eventType = POINTER_INPUT_MAP[eventTypeNormalized]; + var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType; + + var isTouch = (pointerType == INPUT_TYPE_TOUCH); + + // get index of the event in the store + var storeIndex = inArray(store, ev.pointerId, 'pointerId'); + + // start and mouse must be down + if (eventType & INPUT_START && (ev.button === 0 || isTouch)) { + if (storeIndex < 0) { + store.push(ev); + storeIndex = store.length - 1; + } + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + removePointer = true; + } + + // it not found, so the pointer hasn't been down (so it's probably a hover) + if (storeIndex < 0) { + return; + } + + // update the event in the store + store[storeIndex] = ev; + + this.callback(this.manager, eventType, { + pointers: store, + changedPointers: [ev], + pointerType: pointerType, + srcEvent: ev + }); + + if (removePointer) { + // remove from the store + store.splice(storeIndex, 1); + } + } +}); + +var SINGLE_TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL +}; + +var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart'; +var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel'; + +/** + * Touch events input + * @constructor + * @extends Input + */ +function SingleTouchInput() { + this.evTarget = SINGLE_TOUCH_TARGET_EVENTS; + this.evWin = SINGLE_TOUCH_WINDOW_EVENTS; + this.started = false; + + Input.apply(this, arguments); +} + +inherit(SingleTouchInput, Input, { + handler: function TEhandler(ev) { + var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; + + // should we handle the touch events? + if (type === INPUT_START) { + this.started = true; + } + + if (!this.started) { + return; + } + + var touches = normalizeSingleTouches.call(this, ev, type); + + // when done, reset the started state + if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) { + this.started = false; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } +}); + +/** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ +function normalizeSingleTouches(ev, type) { + var all = toArray(ev.touches); + var changed = toArray(ev.changedTouches); + + if (type & (INPUT_END | INPUT_CANCEL)) { + all = uniqueArray(all.concat(changed), 'identifier', true); + } + + return [all, changed]; +} + +var TOUCH_INPUT_MAP = { + touchstart: INPUT_START, + touchmove: INPUT_MOVE, + touchend: INPUT_END, + touchcancel: INPUT_CANCEL +}; + +var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel'; + +/** + * Multi-user touch events input + * @constructor + * @extends Input + */ +function TouchInput() { + this.evTarget = TOUCH_TARGET_EVENTS; + this.targetIds = {}; + + Input.apply(this, arguments); +} + +inherit(TouchInput, Input, { + handler: function MTEhandler(ev) { + var type = TOUCH_INPUT_MAP[ev.type]; + var touches = getTouches.call(this, ev, type); + if (!touches) { + return; + } + + this.callback(this.manager, type, { + pointers: touches[0], + changedPointers: touches[1], + pointerType: INPUT_TYPE_TOUCH, + srcEvent: ev + }); + } +}); + +/** + * @this {TouchInput} + * @param {Object} ev + * @param {Number} type flag + * @returns {undefined|Array} [all, changed] + */ +function getTouches(ev, type) { + var allTouches = toArray(ev.touches); + var targetIds = this.targetIds; + + // when there is only one touch, the process can be simplified + if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) { + targetIds[allTouches[0].identifier] = true; + return [allTouches, allTouches]; + } + + var i, + targetTouches, + changedTouches = toArray(ev.changedTouches), + changedTargetTouches = [], + target = this.target; + + // get target touches from touches + targetTouches = allTouches.filter(function(touch) { + return hasParent(touch.target, target); + }); + + // collect touches + if (type === INPUT_START) { + i = 0; + while (i < targetTouches.length) { + targetIds[targetTouches[i].identifier] = true; + i++; + } + } + + // filter changed touches to only contain touches that exist in the collected target ids + i = 0; + while (i < changedTouches.length) { + if (targetIds[changedTouches[i].identifier]) { + changedTargetTouches.push(changedTouches[i]); + } + + // cleanup removed touches + if (type & (INPUT_END | INPUT_CANCEL)) { + delete targetIds[changedTouches[i].identifier]; + } + i++; + } + + if (!changedTargetTouches.length) { + return; + } + + return [ + // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel' + uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), + changedTargetTouches + ]; +} + +/** + * Combined touch and mouse input + * + * Touch has a higher priority then mouse, and while touching no mouse events are allowed. + * This because touch devices also emit mouse events while doing a touch. + * + * @constructor + * @extends Input + */ + +var DEDUP_TIMEOUT = 2500; +var DEDUP_DISTANCE = 25; + +function TouchMouseInput() { + Input.apply(this, arguments); + + var handler = bindFn(this.handler, this); + this.touch = new TouchInput(this.manager, handler); + this.mouse = new MouseInput(this.manager, handler); + + this.primaryTouch = null; + this.lastTouches = []; +} + +inherit(TouchMouseInput, Input, { + /** + * handle mouse and touch events + * @param {Hammer} manager + * @param {String} inputEvent + * @param {Object} inputData + */ + handler: function TMEhandler(manager, inputEvent, inputData) { + var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH), + isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE); + + if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) { + return; + } + + // when we're in a touch event, record touches to de-dupe synthetic mouse event + if (isTouch) { + recordTouches.call(this, inputEvent, inputData); + } else if (isMouse && isSyntheticEvent.call(this, inputData)) { + return; + } + + this.callback(manager, inputEvent, inputData); + }, + + /** + * remove the event listeners + */ + destroy: function destroy() { + this.touch.destroy(); + this.mouse.destroy(); + } +}); + +function recordTouches(eventType, eventData) { + if (eventType & INPUT_START) { + this.primaryTouch = eventData.changedPointers[0].identifier; + setLastTouch.call(this, eventData); + } else if (eventType & (INPUT_END | INPUT_CANCEL)) { + setLastTouch.call(this, eventData); + } +} + +function setLastTouch(eventData) { + var touch = eventData.changedPointers[0]; + + if (touch.identifier === this.primaryTouch) { + var lastTouch = {x: touch.clientX, y: touch.clientY}; + this.lastTouches.push(lastTouch); + var lts = this.lastTouches; + var removeLastTouch = function() { + var i = lts.indexOf(lastTouch); + if (i > -1) { + lts.splice(i, 1); + } + }; + setTimeout(removeLastTouch, DEDUP_TIMEOUT); + } +} + +function isSyntheticEvent(eventData) { + var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY; + for (var i = 0; i < this.lastTouches.length; i++) { + var t = this.lastTouches[i]; + var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y); + if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) { + return true; + } + } + return false; +} + +var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction'); +var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined; + +// magical touchAction value +var TOUCH_ACTION_COMPUTE = 'compute'; +var TOUCH_ACTION_AUTO = 'auto'; +var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented +var TOUCH_ACTION_NONE = 'none'; +var TOUCH_ACTION_PAN_X = 'pan-x'; +var TOUCH_ACTION_PAN_Y = 'pan-y'; +var TOUCH_ACTION_MAP = getTouchActionProps(); + +/** + * Touch Action + * sets the touchAction property or uses the js alternative + * @param {Manager} manager + * @param {String} value + * @constructor + */ +function TouchAction(manager, value) { + this.manager = manager; + this.set(value); +} + +TouchAction.prototype = { + /** + * set the touchAction value on the element or enable the polyfill + * @param {String} value + */ + set: function(value) { + // find out the touch-action by the event handlers + if (value == TOUCH_ACTION_COMPUTE) { + value = this.compute(); + } + + if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) { + this.manager.element.style[PREFIXED_TOUCH_ACTION] = value; + } + this.actions = value.toLowerCase().trim(); + }, + + /** + * just re-set the touchAction value + */ + update: function() { + this.set(this.manager.options.touchAction); + }, + + /** + * compute the value for the touchAction property based on the recognizer's settings + * @returns {String} value + */ + compute: function() { + var actions = []; + each(this.manager.recognizers, function(recognizer) { + if (boolOrFn(recognizer.options.enable, [recognizer])) { + actions = actions.concat(recognizer.getTouchAction()); + } + }); + return cleanTouchActions(actions.join(' ')); + }, + + /** + * this method is called on each input cycle and provides the preventing of the browser behavior + * @param {Object} input + */ + preventDefaults: function(input) { + var srcEvent = input.srcEvent; + var direction = input.offsetDirection; + + // if the touch action did prevented once this session + if (this.manager.session.prevented) { + srcEvent.preventDefault(); + return; + } + + var actions = this.actions; + var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE]; + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y]; + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X]; + + if (hasNone) { + //do not prevent defaults if this is a tap gesture + + var isTapPointer = input.pointers.length === 1; + var isTapMovement = input.distance < 2; + var isTapTouchTime = input.deltaTime < 250; + + if (isTapPointer && isTapMovement && isTapTouchTime) { + return; + } + } + + if (hasPanX && hasPanY) { + // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent + return; + } + + if (hasNone || + (hasPanY && direction & DIRECTION_HORIZONTAL) || + (hasPanX && direction & DIRECTION_VERTICAL)) { + return this.preventSrc(srcEvent); + } + }, + + /** + * call preventDefault to prevent the browser's default behavior (scrolling in most cases) + * @param {Object} srcEvent + */ + preventSrc: function(srcEvent) { + this.manager.session.prevented = true; + srcEvent.preventDefault(); + } +}; + +/** + * when the touchActions are collected they are not a valid value, so we need to clean things up. * + * @param {String} actions + * @returns {*} + */ +function cleanTouchActions(actions) { + // none + if (inStr(actions, TOUCH_ACTION_NONE)) { + return TOUCH_ACTION_NONE; + } + + var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X); + var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); + + // if both pan-x and pan-y are set (different recognizers + // for different directions, e.g. horizontal pan but vertical swipe?) + // we need none (as otherwise with pan-x pan-y combined none of these + // recognizers will work, since the browser would handle all panning + if (hasPanX && hasPanY) { + return TOUCH_ACTION_NONE; + } + + // pan-x OR pan-y + if (hasPanX || hasPanY) { + return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y; + } + + // manipulation + if (inStr(actions, TOUCH_ACTION_MANIPULATION)) { + return TOUCH_ACTION_MANIPULATION; + } + + return TOUCH_ACTION_AUTO; +} + +function getTouchActionProps() { + if (!NATIVE_TOUCH_ACTION) { + return false; + } + var touchMap = {}; + var cssSupports = window.CSS && window.CSS.supports; + ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) { + + // If css.supports is not supported but there is native touch-action assume it supports + // all values. This is the case for IE 10 and 11. + touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true; + }); + return touchMap; +} + +/** + * Recognizer flow explained; * + * All recognizers have the initial state of POSSIBLE when a input session starts. + * The definition of a input session is from the first input until the last input, with all it's movement in it. * + * Example session for mouse-input: mousedown -> mousemove -> mouseup + * + * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed + * which determines with state it should be. + * + * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to + * POSSIBLE to give it another change on the next cycle. + * + * Possible + * | + * +-----+---------------+ + * | | + * +-----+-----+ | + * | | | + * Failed Cancelled | + * +-------+------+ + * | | + * Recognized Began + * | + * Changed + * | + * Ended/Recognized + */ +var STATE_POSSIBLE = 1; +var STATE_BEGAN = 2; +var STATE_CHANGED = 4; +var STATE_ENDED = 8; +var STATE_RECOGNIZED = STATE_ENDED; +var STATE_CANCELLED = 16; +var STATE_FAILED = 32; + +/** + * Recognizer + * Every recognizer needs to extend from this class. + * @constructor + * @param {Object} options + */ +function Recognizer(options) { + this.options = assign({}, this.defaults, options || {}); + + this.id = uniqueId(); + + this.manager = null; + + // default is enable true + this.options.enable = ifUndefined(this.options.enable, true); + + this.state = STATE_POSSIBLE; + + this.simultaneous = {}; + this.requireFail = []; +} + +Recognizer.prototype = { + /** + * @virtual + * @type {Object} + */ + defaults: {}, + + /** + * set options + * @param {Object} options + * @return {Recognizer} + */ + set: function(options) { + assign(this.options, options); + + // also update the touchAction, in case something changed about the directions/enabled state + this.manager && this.manager.touchAction.update(); + return this; + }, + + /** + * recognize simultaneous with an other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + recognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) { + return this; + } + + var simultaneous = this.simultaneous; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (!simultaneous[otherRecognizer.id]) { + simultaneous[otherRecognizer.id] = otherRecognizer; + otherRecognizer.recognizeWith(this); + } + return this; + }, + + /** + * drop the simultaneous link. it doesnt remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRecognizeWith: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + delete this.simultaneous[otherRecognizer.id]; + return this; + }, + + /** + * recognizer can only run when an other is failing + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + requireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) { + return this; + } + + var requireFail = this.requireFail; + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + if (inArray(requireFail, otherRecognizer) === -1) { + requireFail.push(otherRecognizer); + otherRecognizer.requireFailure(this); + } + return this; + }, + + /** + * drop the requireFailure link. it does not remove the link on the other recognizer. + * @param {Recognizer} otherRecognizer + * @returns {Recognizer} this + */ + dropRequireFailure: function(otherRecognizer) { + if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) { + return this; + } + + otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this); + var index = inArray(this.requireFail, otherRecognizer); + if (index > -1) { + this.requireFail.splice(index, 1); + } + return this; + }, + + /** + * has require failures boolean + * @returns {boolean} + */ + hasRequireFailures: function() { + return this.requireFail.length > 0; + }, + + /** + * if the recognizer can recognize simultaneous with an other recognizer + * @param {Recognizer} otherRecognizer + * @returns {Boolean} + */ + canRecognizeWith: function(otherRecognizer) { + return !!this.simultaneous[otherRecognizer.id]; + }, + + /** + * You should use `tryEmit` instead of `emit` directly to check + * that all the needed recognizers has failed before emitting. + * @param {Object} input + */ + emit: function(input) { + var self = this; + var state = this.state; + + function emit(event) { + self.manager.emit(event, input); + } + + // 'panstart' and 'panmove' + if (state < STATE_ENDED) { + emit(self.options.event + stateStr(state)); + } + + emit(self.options.event); // simple 'eventName' events + + if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...) + emit(input.additionalEvent); + } + + // panend and pancancel + if (state >= STATE_ENDED) { + emit(self.options.event + stateStr(state)); + } + }, + + /** + * Check that all the require failure recognizers has failed, + * if true, it emits a gesture event, + * otherwise, setup the state to FAILED. + * @param {Object} input + */ + tryEmit: function(input) { + if (this.canEmit()) { + return this.emit(input); + } + // it's failing anyway + this.state = STATE_FAILED; + }, + + /** + * can we emit? + * @returns {boolean} + */ + canEmit: function() { + var i = 0; + while (i < this.requireFail.length) { + if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) { + return false; + } + i++; + } + return true; + }, + + /** + * update the recognizer + * @param {Object} inputData + */ + recognize: function(inputData) { + // make a new copy of the inputData + // so we can change the inputData without messing up the other recognizers + var inputDataClone = assign({}, inputData); + + // is is enabled and allow recognizing? + if (!boolOrFn(this.options.enable, [this, inputDataClone])) { + this.reset(); + this.state = STATE_FAILED; + return; + } + + // reset when we've reached the end + if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) { + this.state = STATE_POSSIBLE; + } + + this.state = this.process(inputDataClone); + + // the recognizer has recognized a gesture + // so trigger an event + if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) { + this.tryEmit(inputDataClone); + } + }, + + /** + * return the state of the recognizer + * the actual recognizing happens in this method + * @virtual + * @param {Object} inputData + * @returns {Const} STATE + */ + process: function(inputData) { }, // jshint ignore:line + + /** + * return the preferred touch-action + * @virtual + * @returns {Array} + */ + getTouchAction: function() { }, + + /** + * called when the gesture isn't allowed to recognize + * like when another is being recognized or it is disabled + * @virtual + */ + reset: function() { } +}; + +/** + * get a usable string, used as event postfix + * @param {Const} state + * @returns {String} state + */ +function stateStr(state) { + if (state & STATE_CANCELLED) { + return 'cancel'; + } else if (state & STATE_ENDED) { + return 'end'; + } else if (state & STATE_CHANGED) { + return 'move'; + } else if (state & STATE_BEGAN) { + return 'start'; + } + return ''; +} + +/** + * direction cons to string + * @param {Const} direction + * @returns {String} + */ +function directionStr(direction) { + if (direction == DIRECTION_DOWN) { + return 'down'; + } else if (direction == DIRECTION_UP) { + return 'up'; + } else if (direction == DIRECTION_LEFT) { + return 'left'; + } else if (direction == DIRECTION_RIGHT) { + return 'right'; + } + return ''; +} + +/** + * get a recognizer by name if it is bound to a manager + * @param {Recognizer|String} otherRecognizer + * @param {Recognizer} recognizer + * @returns {Recognizer} + */ +function getRecognizerByNameIfManager(otherRecognizer, recognizer) { + var manager = recognizer.manager; + if (manager) { + return manager.get(otherRecognizer); + } + return otherRecognizer; +} + +/** + * This recognizer is just used as a base for the simple attribute recognizers. + * @constructor + * @extends Recognizer + */ +function AttrRecognizer() { + Recognizer.apply(this, arguments); +} + +inherit(AttrRecognizer, Recognizer, { + /** + * @namespace + * @memberof AttrRecognizer + */ + defaults: { + /** + * @type {Number} + * @default 1 + */ + pointers: 1 + }, + + /** + * Used to check if it the recognizer receives valid input, like input.distance > 10. + * @memberof AttrRecognizer + * @param {Object} input + * @returns {Boolean} recognized + */ + attrTest: function(input) { + var optionPointers = this.options.pointers; + return optionPointers === 0 || input.pointers.length === optionPointers; + }, + + /** + * Process the input and return the state for the recognizer + * @memberof AttrRecognizer + * @param {Object} input + * @returns {*} State + */ + process: function(input) { + var state = this.state; + var eventType = input.eventType; + + var isRecognized = state & (STATE_BEGAN | STATE_CHANGED); + var isValid = this.attrTest(input); + + // on cancel input and we've recognized before, return STATE_CANCELLED + if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) { + return state | STATE_CANCELLED; + } else if (isRecognized || isValid) { + if (eventType & INPUT_END) { + return state | STATE_ENDED; + } else if (!(state & STATE_BEGAN)) { + return STATE_BEGAN; + } + return state | STATE_CHANGED; + } + return STATE_FAILED; + } +}); + +/** + * Pan + * Recognized when the pointer is down and moved in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ +function PanRecognizer() { + AttrRecognizer.apply(this, arguments); + + this.pX = null; + this.pY = null; +} + +inherit(PanRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PanRecognizer + */ + defaults: { + event: 'pan', + threshold: 10, + pointers: 1, + direction: DIRECTION_ALL + }, + + getTouchAction: function() { + var direction = this.options.direction; + var actions = []; + if (direction & DIRECTION_HORIZONTAL) { + actions.push(TOUCH_ACTION_PAN_Y); + } + if (direction & DIRECTION_VERTICAL) { + actions.push(TOUCH_ACTION_PAN_X); + } + return actions; + }, + + directionTest: function(input) { + var options = this.options; + var hasMoved = true; + var distance = input.distance; + var direction = input.direction; + var x = input.deltaX; + var y = input.deltaY; + + // lock to axis? + if (!(direction & options.direction)) { + if (options.direction & DIRECTION_HORIZONTAL) { + direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT; + hasMoved = x != this.pX; + distance = Math.abs(input.deltaX); + } else { + direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN; + hasMoved = y != this.pY; + distance = Math.abs(input.deltaY); + } + } + input.direction = direction; + return hasMoved && distance > options.threshold && direction & options.direction; + }, + + attrTest: function(input) { + return AttrRecognizer.prototype.attrTest.call(this, input) && + (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input))); + }, + + emit: function(input) { + + this.pX = input.deltaX; + this.pY = input.deltaY; + + var direction = directionStr(input.direction); + + if (direction) { + input.additionalEvent = this.options.event + direction; + } + this._super.emit.call(this, input); + } +}); + +/** + * Pinch + * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out). + * @constructor + * @extends AttrRecognizer + */ +function PinchRecognizer() { + AttrRecognizer.apply(this, arguments); +} + +inherit(PinchRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'pinch', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN); + }, + + emit: function(input) { + if (input.scale !== 1) { + var inOut = input.scale < 1 ? 'in' : 'out'; + input.additionalEvent = this.options.event + inOut; + } + this._super.emit.call(this, input); + } +}); + +/** + * Press + * Recognized when the pointer is down for x ms without any movement. + * @constructor + * @extends Recognizer + */ +function PressRecognizer() { + Recognizer.apply(this, arguments); + + this._timer = null; + this._input = null; +} + +inherit(PressRecognizer, Recognizer, { + /** + * @namespace + * @memberof PressRecognizer + */ + defaults: { + event: 'press', + pointers: 1, + time: 251, // minimal time of the pointer to be pressed + threshold: 9 // a minimal movement is ok, but keep it low + }, + + getTouchAction: function() { + return [TOUCH_ACTION_AUTO]; + }, + + process: function(input) { + var options = this.options; + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTime = input.deltaTime > options.time; + + this._input = input; + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) { + this.reset(); + } else if (input.eventType & INPUT_START) { + this.reset(); + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.time, this); + } else if (input.eventType & INPUT_END) { + return STATE_RECOGNIZED; + } + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function(input) { + if (this.state !== STATE_RECOGNIZED) { + return; + } + + if (input && (input.eventType & INPUT_END)) { + this.manager.emit(this.options.event + 'up', input); + } else { + this._input.timeStamp = now(); + this.manager.emit(this.options.event, this._input); + } + } +}); + +/** + * Rotate + * Recognized when two or more pointer are moving in a circular motion. + * @constructor + * @extends AttrRecognizer + */ +function RotateRecognizer() { + AttrRecognizer.apply(this, arguments); +} + +inherit(RotateRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof RotateRecognizer + */ + defaults: { + event: 'rotate', + threshold: 0, + pointers: 2 + }, + + getTouchAction: function() { + return [TOUCH_ACTION_NONE]; + }, + + attrTest: function(input) { + return this._super.attrTest.call(this, input) && + (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN); + } +}); + +/** + * Swipe + * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction. + * @constructor + * @extends AttrRecognizer + */ +function SwipeRecognizer() { + AttrRecognizer.apply(this, arguments); +} + +inherit(SwipeRecognizer, AttrRecognizer, { + /** + * @namespace + * @memberof SwipeRecognizer + */ + defaults: { + event: 'swipe', + threshold: 10, + velocity: 0.3, + direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL, + pointers: 1 + }, + + getTouchAction: function() { + return PanRecognizer.prototype.getTouchAction.call(this); + }, + + attrTest: function(input) { + var direction = this.options.direction; + var velocity; + + if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) { + velocity = input.overallVelocity; + } else if (direction & DIRECTION_HORIZONTAL) { + velocity = input.overallVelocityX; + } else if (direction & DIRECTION_VERTICAL) { + velocity = input.overallVelocityY; + } + + return this._super.attrTest.call(this, input) && + direction & input.offsetDirection && + input.distance > this.options.threshold && + input.maxPointers == this.options.pointers && + abs(velocity) > this.options.velocity && input.eventType & INPUT_END; + }, + + emit: function(input) { + var direction = directionStr(input.offsetDirection); + if (direction) { + this.manager.emit(this.options.event + direction, input); + } + + this.manager.emit(this.options.event, input); + } +}); + +/** + * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur + * between the given interval and position. The delay option can be used to recognize multi-taps without firing + * a single tap. + * + * The eventData from the emitted event contains the property `tapCount`, which contains the amount of + * multi-taps being recognized. + * @constructor + * @extends Recognizer + */ +function TapRecognizer() { + Recognizer.apply(this, arguments); + + // previous time and center, + // used for tap counting + this.pTime = false; + this.pCenter = false; + + this._timer = null; + this._input = null; + this.count = 0; +} + +inherit(TapRecognizer, Recognizer, { + /** + * @namespace + * @memberof PinchRecognizer + */ + defaults: { + event: 'tap', + pointers: 1, + taps: 1, + interval: 300, // max time between the multi-tap taps + time: 250, // max time of the pointer to be down (like finger on the screen) + threshold: 9, // a minimal movement is ok, but keep it low + posThreshold: 10 // a multi-tap can be a bit off the initial position + }, + + getTouchAction: function() { + return [TOUCH_ACTION_MANIPULATION]; + }, + + process: function(input) { + var options = this.options; + + var validPointers = input.pointers.length === options.pointers; + var validMovement = input.distance < options.threshold; + var validTouchTime = input.deltaTime < options.time; + + this.reset(); + + if ((input.eventType & INPUT_START) && (this.count === 0)) { + return this.failTimeout(); + } + + // we only allow little movement + // and we've reached an end event, so a tap is possible + if (validMovement && validTouchTime && validPointers) { + if (input.eventType != INPUT_END) { + return this.failTimeout(); + } + + var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true; + var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold; + + this.pTime = input.timeStamp; + this.pCenter = input.center; + + if (!validMultiTap || !validInterval) { + this.count = 1; + } else { + this.count += 1; + } + + this._input = input; + + // if tap count matches we have recognized it, + // else it has began recognizing... + var tapCount = this.count % options.taps; + if (tapCount === 0) { + // no failing requirements, immediately trigger the tap event + // or wait as long as the multitap interval to trigger + if (!this.hasRequireFailures()) { + return STATE_RECOGNIZED; + } else { + this._timer = setTimeoutContext(function() { + this.state = STATE_RECOGNIZED; + this.tryEmit(); + }, options.interval, this); + return STATE_BEGAN; + } + } + } + return STATE_FAILED; + }, + + failTimeout: function() { + this._timer = setTimeoutContext(function() { + this.state = STATE_FAILED; + }, this.options.interval, this); + return STATE_FAILED; + }, + + reset: function() { + clearTimeout(this._timer); + }, + + emit: function() { + if (this.state == STATE_RECOGNIZED) { + this._input.tapCount = this.count; + this.manager.emit(this.options.event, this._input); + } + } +}); + +/** + * Simple way to create a manager with a default set of recognizers. + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ +function Hammer(element, options) { + options = options || {}; + options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset); + return new Manager(element, options); +} + +/** + * @const {string} + */ +Hammer.VERSION = '2.0.7'; + +/** + * default settings + * @namespace + */ +Hammer.defaults = { + /** + * set if DOM events are being triggered. + * But this is slower and unused by simple implementations, so disabled by default. + * @type {Boolean} + * @default false + */ + domEvents: false, + + /** + * The value for the touchAction property/fallback. + * When set to `compute` it will magically set the correct value based on the added recognizers. + * @type {String} + * @default compute + */ + touchAction: TOUCH_ACTION_COMPUTE, + + /** + * @type {Boolean} + * @default true + */ + enable: true, + + /** + * EXPERIMENTAL FEATURE -- can be removed/changed + * Change the parent input target element. + * If Null, then it is being set the to main element. + * @type {Null|EventTarget} + * @default null + */ + inputTarget: null, + + /** + * force an input class + * @type {Null|Function} + * @default null + */ + inputClass: null, + + /** + * Default recognizer setup when calling `Hammer()` + * When creating a new Manager these will be skipped. + * @type {Array} + */ + preset: [ + // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...] + [RotateRecognizer, {enable: false}], + [PinchRecognizer, {enable: false}, ['rotate']], + [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}], + [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']], + [TapRecognizer], + [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']], + [PressRecognizer] + ], + + /** + * Some CSS properties can be used to improve the working of Hammer. + * Add them to this method and they will be set when creating a new Manager. + * @namespace + */ + cssProps: { + /** + * Disables text selection to improve the dragging gesture. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userSelect: 'none', + + /** + * Disable the Windows Phone grippers when pressing an element. + * @type {String} + * @default 'none' + */ + touchSelect: 'none', + + /** + * Disables the default callout shown when you touch and hold a touch target. + * On iOS, when you touch and hold a touch target such as a link, Safari displays + * a callout containing information about the link. This property allows you to disable that callout. + * @type {String} + * @default 'none' + */ + touchCallout: 'none', + + /** + * Specifies whether zooming is enabled. Used by IE10> + * @type {String} + * @default 'none' + */ + contentZooming: 'none', + + /** + * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers. + * @type {String} + * @default 'none' + */ + userDrag: 'none', + + /** + * Overrides the highlight color shown when the user taps a link or a JavaScript + * clickable element in iOS. This property obeys the alpha value, if specified. + * @type {String} + * @default 'rgba(0,0,0,0)' + */ + tapHighlightColor: 'rgba(0,0,0,0)' + } +}; + +var STOP = 1; +var FORCED_STOP = 2; + +/** + * Manager + * @param {HTMLElement} element + * @param {Object} [options] + * @constructor + */ +function Manager(element, options) { + this.options = assign({}, Hammer.defaults, options || {}); + + this.options.inputTarget = this.options.inputTarget || element; + + this.handlers = {}; + this.session = {}; + this.recognizers = []; + this.oldCssProps = {}; + + this.element = element; + this.input = createInputInstance(this); + this.touchAction = new TouchAction(this, this.options.touchAction); + + toggleCssProps(this, true); + + each(this.options.recognizers, function(item) { + var recognizer = this.add(new (item[0])(item[1])); + item[2] && recognizer.recognizeWith(item[2]); + item[3] && recognizer.requireFailure(item[3]); + }, this); +} + +Manager.prototype = { + /** + * set options + * @param {Object} options + * @returns {Manager} + */ + set: function(options) { + assign(this.options, options); + + // Options that need a little more setup + if (options.touchAction) { + this.touchAction.update(); + } + if (options.inputTarget) { + // Clean up existing event listeners and reinitialize + this.input.destroy(); + this.input.target = options.inputTarget; + this.input.init(); + } + return this; + }, + + /** + * stop recognizing for this session. + * This session will be discarded, when a new [input]start event is fired. + * When forced, the recognizer cycle is stopped immediately. + * @param {Boolean} [force] + */ + stop: function(force) { + this.session.stopped = force ? FORCED_STOP : STOP; + }, + + /** + * run the recognizers! + * called by the inputHandler function on every movement of the pointers (touches) + * it walks through all the recognizers and tries to detect the gesture that is being made + * @param {Object} inputData + */ + recognize: function(inputData) { + var session = this.session; + if (session.stopped) { + return; + } + + // run the touch-action polyfill + this.touchAction.preventDefaults(inputData); + + var recognizer; + var recognizers = this.recognizers; + + // this holds the recognizer that is being recognized. + // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED + // if no recognizer is detecting a thing, it is set to `null` + var curRecognizer = session.curRecognizer; + + // reset when the last recognizer is recognized + // or when we're in a new session + if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) { + curRecognizer = session.curRecognizer = null; + } + + var i = 0; + while (i < recognizers.length) { + recognizer = recognizers[i]; + + // find out if we are allowed try to recognize the input for this one. + // 1. allow if the session is NOT forced stopped (see the .stop() method) + // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one + // that is being recognized. + // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer. + // this can be setup with the `recognizeWith()` method on the recognizer. + if (session.stopped !== FORCED_STOP && ( // 1 + !curRecognizer || recognizer == curRecognizer || // 2 + recognizer.canRecognizeWith(curRecognizer))) { // 3 + recognizer.recognize(inputData); + } else { + recognizer.reset(); + } + + // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the + // current active recognizer. but only if we don't already have an active recognizer + if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) { + curRecognizer = session.curRecognizer = recognizer; + } + i++; + } + }, + + /** + * get a recognizer by its event name. + * @param {Recognizer|String} recognizer + * @returns {Recognizer|Null} + */ + get: function(recognizer) { + if (recognizer instanceof Recognizer) { + return recognizer; + } + + var recognizers = this.recognizers; + for (var i = 0; i < recognizers.length; i++) { + if (recognizers[i].options.event == recognizer) { + return recognizers[i]; + } + } + return null; + }, + + /** + * add a recognizer to the manager + * existing recognizers with the same event name will be removed + * @param {Recognizer} recognizer + * @returns {Recognizer|Manager} + */ + add: function(recognizer) { + if (invokeArrayArg(recognizer, 'add', this)) { + return this; + } + + // remove existing + var existing = this.get(recognizer.options.event); + if (existing) { + this.remove(existing); + } + + this.recognizers.push(recognizer); + recognizer.manager = this; + + this.touchAction.update(); + return recognizer; + }, + + /** + * remove a recognizer by name or instance + * @param {Recognizer|String} recognizer + * @returns {Manager} + */ + remove: function(recognizer) { + if (invokeArrayArg(recognizer, 'remove', this)) { + return this; + } + + recognizer = this.get(recognizer); + + // let's make sure this recognizer exists + if (recognizer) { + var recognizers = this.recognizers; + var index = inArray(recognizers, recognizer); + + if (index !== -1) { + recognizers.splice(index, 1); + this.touchAction.update(); + } + } + + return this; + }, + + /** + * bind event + * @param {String} events + * @param {Function} handler + * @returns {EventEmitter} this + */ + on: function(events, handler) { + if (events === undefined) { + return; + } + if (handler === undefined) { + return; + } + + var handlers = this.handlers; + each(splitStr(events), function(event) { + handlers[event] = handlers[event] || []; + handlers[event].push(handler); + }); + return this; + }, + + /** + * unbind event, leave emit blank to remove all handlers + * @param {String} events + * @param {Function} [handler] + * @returns {EventEmitter} this + */ + off: function(events, handler) { + if (events === undefined) { + return; + } + + var handlers = this.handlers; + each(splitStr(events), function(event) { + if (!handler) { + delete handlers[event]; + } else { + handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1); + } + }); + return this; + }, + + /** + * emit event to the listeners + * @param {String} event + * @param {Object} data + */ + emit: function(event, data) { + // we also want to trigger dom events + if (this.options.domEvents) { + triggerDomEvent(event, data); + } + + // no handlers, so skip it all + var handlers = this.handlers[event] && this.handlers[event].slice(); + if (!handlers || !handlers.length) { + return; + } + + data.type = event; + data.preventDefault = function() { + data.srcEvent.preventDefault(); + }; + + var i = 0; + while (i < handlers.length) { + handlers[i](data); + i++; + } + }, + + /** + * destroy the manager and unbinds all events + * it doesn't unbind dom events, that is the user own responsibility + */ + destroy: function() { + this.element && toggleCssProps(this, false); + + this.handlers = {}; + this.session = {}; + this.input.destroy(); + this.element = null; + } +}; + +/** + * add/remove the css properties as defined in manager.options.cssProps + * @param {Manager} manager + * @param {Boolean} add + */ +function toggleCssProps(manager, add) { + var element = manager.element; + if (!element.style) { + return; + } + var prop; + each(manager.options.cssProps, function(value, name) { + prop = prefixed(element.style, name); + if (add) { + manager.oldCssProps[prop] = element.style[prop]; + element.style[prop] = value; + } else { + element.style[prop] = manager.oldCssProps[prop] || ''; + } + }); + if (!add) { + manager.oldCssProps = {}; + } +} + +/** + * trigger dom event + * @param {String} event + * @param {Object} data + */ +function triggerDomEvent(event, data) { + var gestureEvent = document.createEvent('Event'); + gestureEvent.initEvent(event, true, true); + gestureEvent.gesture = data; + data.target.dispatchEvent(gestureEvent); +} + +assign(Hammer, { + INPUT_START: INPUT_START, + INPUT_MOVE: INPUT_MOVE, + INPUT_END: INPUT_END, + INPUT_CANCEL: INPUT_CANCEL, + + STATE_POSSIBLE: STATE_POSSIBLE, + STATE_BEGAN: STATE_BEGAN, + STATE_CHANGED: STATE_CHANGED, + STATE_ENDED: STATE_ENDED, + STATE_RECOGNIZED: STATE_RECOGNIZED, + STATE_CANCELLED: STATE_CANCELLED, + STATE_FAILED: STATE_FAILED, + + DIRECTION_NONE: DIRECTION_NONE, + DIRECTION_LEFT: DIRECTION_LEFT, + DIRECTION_RIGHT: DIRECTION_RIGHT, + DIRECTION_UP: DIRECTION_UP, + DIRECTION_DOWN: DIRECTION_DOWN, + DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL, + DIRECTION_VERTICAL: DIRECTION_VERTICAL, + DIRECTION_ALL: DIRECTION_ALL, + + Manager: Manager, + Input: Input, + TouchAction: TouchAction, + + TouchInput: TouchInput, + MouseInput: MouseInput, + PointerEventInput: PointerEventInput, + TouchMouseInput: TouchMouseInput, + SingleTouchInput: SingleTouchInput, + + Recognizer: Recognizer, + AttrRecognizer: AttrRecognizer, + Tap: TapRecognizer, + Pan: PanRecognizer, + Swipe: SwipeRecognizer, + Pinch: PinchRecognizer, + Rotate: RotateRecognizer, + Press: PressRecognizer, + + on: addEventListeners, + off: removeEventListeners, + each: each, + merge: merge, + extend: extend, + assign: assign, + inherit: inherit, + bindFn: bindFn, + prefixed: prefixed +}); + +// this prevents errors when Hammer is loaded in the presence of an AMD +// style loader but by script tag, not by the loader. +var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line +freeGlobal.Hammer = Hammer; + +if (typeof define === 'function' && define.amd) { + define(function() { + return Hammer; + }); +} else if (typeof module != 'undefined' && module.exports) { + module.exports = Hammer; +} else { + window[exportName] = Hammer; +} + +})(window, document, 'Hammer'); diff --git a/patches/01_hardcode_git_hash.patch b/patches/01_hardcode_git_hash.patch new file mode 100644 index 0000000..08baf16 --- /dev/null +++ b/patches/01_hardcode_git_hash.patch @@ -0,0 +1,29 @@ +From: Anton Gladky +Date: Thu, 12 May 2022 16:48:46 -0500 +Subject: Manually specify git commit hash + +Revise on every upstream update! + +Forwarded: not-needed +Last-Update: 2022-06-30 +=================================================================== +--- + CMakeLists.txt | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 399e2ca..0446e1b 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -34,9 +34,9 @@ endif() + # 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) ++# include(GetGitCommitHash) + # and instead uncomment the following, adding the complete git hash of the checkout you are using: +-# set(GIT_COMMIT_HASH 0000000000000000000000000000000000000000) ++set(GIT_COMMIT_HASH 70bde63cb32a7f049fa56cbdf924e2695fcb2916) + + string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH) + project(solvespace diff --git a/patches/02_add_debian_pkg_version.patch b/patches/02_add_debian_pkg_version.patch new file mode 100644 index 0000000..ec574f6 --- /dev/null +++ b/patches/02_add_debian_pkg_version.patch @@ -0,0 +1,22 @@ +From: Ryan Pavlik +Date: Thu, 12 May 2022 16:48:46 -0500 +Subject: Add debian package version to ver string. + +Forwarded: not-needed +--- + src/config.h.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/config.h.in b/src/config.h.in +index 187b9cb..ab0792c 100644 +--- a/src/config.h.in ++++ b/src/config.h.in +@@ -1,7 +1,7 @@ + #ifndef SOLVESPACE_CONFIG_H + #define SOLVESPACE_CONFIG_H + +-#define PACKAGE_VERSION "@PROJECT_VERSION@~@solvespace_GIT_HASH@" ++#define PACKAGE_VERSION "@solvespace_VERSION_MAJOR@.@solvespace_VERSION_MINOR@ (Debian package version @DEBVERSION@)" + #define GIT_HASH_URL "https://github.com/solvespace/solvespace/commit/@solvespace_GIT_HASH@" + + /* Non-OS X *nix only */ diff --git a/patches/03_use_system_threejs.patch b/patches/03_use_system_threejs.patch new file mode 100644 index 0000000..7efb308 --- /dev/null +++ b/patches/03_use_system_threejs.patch @@ -0,0 +1,44 @@ +From: Ryan Pavlik +Date: Thu, 12 May 2022 16:48:46 -0500 +Subject: Use threejs from system. + +Forwarded: not-needed +--- + res/CMakeLists.txt | 1 - + src/export.cpp | 4 ++-- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt +index 7303c6f..78d2bd2 100644 +--- a/res/CMakeLists.txt ++++ b/res/CMakeLists.txt +@@ -295,7 +295,6 @@ add_resources( + shaders/edge.frag + shaders/edge.vert + shaders/outline.vert +- threejs/three-r111.min.js.gz + threejs/hammer-2.0.8.js.gz + threejs/SolveSpaceControls.js) + +diff --git a/src/export.cpp b/src/export.cpp +index f1c331f..d3a47b4 100644 +--- a/src/export.cpp ++++ b/src/export.cpp +@@ -953,7 +953,7 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename + STriangle *tr; + Vector bndl, bndh; + +- const std::string THREE_FN("three-r111.min.js"); ++ const std::string THREE_FN("three.js"); + const std::string HAMMER_FN("hammer-2.0.8.js"); + const std::string CONTROLS_FN("SolveSpaceControls.js"); + +@@ -1016,7 +1016,7 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename + if(filename.HasExtension("html")) { + fprintf(f, htmlbegin, + THREE_FN.c_str(), +- LoadStringFromGzip("threejs/" + THREE_FN + ".gz").c_str(), ++ LoadString("threejs/" + THREE_FN).c_str(), + HAMMER_FN.c_str(), + LoadStringFromGzip("threejs/" + HAMMER_FN + ".gz").c_str(), + CONTROLS_FN.c_str(), diff --git a/patches/04_use_system_unifont.patch b/patches/04_use_system_unifont.patch new file mode 100644 index 0000000..d943865 --- /dev/null +++ b/patches/04_use_system_unifont.patch @@ -0,0 +1,35 @@ +From: Ryan Pavlik +Date: Thu, 12 May 2022 16:48:46 -0500 +Subject: Use Unifont from system + +Forwarded: not-needed +--- + res/CMakeLists.txt | 1 - + src/resource.cpp | 2 +- + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt +index 78d2bd2..64fc439 100644 +--- a/res/CMakeLists.txt ++++ b/res/CMakeLists.txt +@@ -270,7 +270,6 @@ add_resources( + locales/tr_TR.po + locales/ru_RU.po + locales/zh_CN.po +- fonts/unifont.hex.gz + fonts/private/0-check-false.png + fonts/private/1-check-true.png + fonts/private/2-radio-false.png +diff --git a/src/resource.cpp b/src/resource.cpp +index d3fa4ca..f687894 100644 +--- a/src/resource.cpp ++++ b/src/resource.cpp +@@ -669,7 +669,7 @@ size_t BitmapFont::GetWidth(const std::string &str) { + } + + BitmapFont BitmapFont::Create() { +- BitmapFont Font = BitmapFont::From(LoadStringFromGzip("fonts/unifont.hex.gz")); ++ BitmapFont Font = BitmapFont::From(LoadString("fonts/unifont.hex")); + // Unifont doesn't have a glyph for U+0020. + Font.AddGlyph(0x0020, Pixmap::Create(Pixmap::Format::RGB, 8, 16)); + Font.AddGlyph(0xE000, LoadPng("fonts/private/0-check-false.png")); diff --git a/patches/series b/patches/series new file mode 100644 index 0000000..4745fc7 --- /dev/null +++ b/patches/series @@ -0,0 +1,4 @@ +01_hardcode_git_hash.patch +02_add_debian_pkg_version.patch +03_use_system_threejs.patch +04_use_system_unifont.patch diff --git a/rules b/rules new file mode 100755 index 0000000..be9e87b --- /dev/null +++ b/rules @@ -0,0 +1,36 @@ +#!/usr/bin/make -f + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/default.mk + +ifneq (,$(filter $(DEB_HOST_ARCH), armel m68k mips mipsel powerpc sh4)) + export DEB_CXXFLAGS_MAINT_APPEND += -Wl,--no-as-needed -latomic -Wl,--as-needed + export DEB_LDFLAGS_MAINT_APPEND += -Wl,--no-as-needed -latomic -Wl,--as-needed +endif + +# Tell CMake what the package version will be, to embed in the version string. +# We do this for upstream's benefit, in lieu of including a git commit hash. +CMAKEOPTS=-DDEBVERSION=$(DEB_VERSION) +CMAKEOPTS+= -DENABLE_OPENMP=yes +CMAKEOPTS+= -DENABLE_LTO=yes + +#speed up the build if we are skipping the tests +ifneq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) +ifneq (amd64,$(DEB_HOST_ARCH)) +CMAKEOPTS+= -DENABLE_TESTS=off +endif +endif + +%: + dh $@ + +override_dh_auto_configure: + dh_auto_configure -- $(CMAKEOPTS) + +override_dh_auto_test: +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) +ifeq (amd64,$(DEB_HOST_ARCH)) + cd obj-* && $(MAKE) -j$(nproc) test_solvespace +endif +endif diff --git a/solvespace-cli.1 b/solvespace-cli.1 new file mode 100644 index 0000000..f1d77c5 --- /dev/null +++ b/solvespace-cli.1 @@ -0,0 +1,96 @@ +.TH SOLVESPACE 1 "06 Oct 2019" "3.0.0" +.SH NAME +solvespace \- parametric 2d/3d CAD +.SH SYNOPSIS +.B solvespace-cli +.RI " [options] " +.SH "DESCRIPTION" +.B 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. +.PP +.SH COMMON OPTIONS +.TP +.B \-o, \-\-output +For an input file .slvs, replaces the '%' symbol in +with and uses it as output file. For example, when using +\-\-output %-2d.png for input files f/a.slvs and f/b.slvs, output files +f/a-2d.png and f/b-2d.png will be written. +.TP +.B \-v, \-\-view +Selects the camera direction. can be one of "top", "bottom", +"left", "right", "front", "back", or "isometric". +.TP +.B \-t, \-\-chord-tol +Selects the chord tolerance, used for converting exact curves to +piecewise linear, and exact surfaces into triangle meshes. +For export commands, the unit is mm, and the default is 1.0 mm. +For non-export commands, the unit is %, and the default is 1.0 %. +.PP +.SH COMMANDS +.TP +.B thumbnail \-\-output \-\-size \-\-view [\-\-chord-tol ] +Outputs a rendered view of the sketch, like the SolveSpace GUI would. is x, in pixels. Graphics acceleration is not used, and the output may look slightly different from the GUI. +.TP +.B export-view \-\-output \-\-view [\-\-chord-tol ] +Exports a view of the sketch, in a 2d vector format. +.TP +.B export-wireframe \-\-output [\-\-chord-tol ] +Exports a wireframe of the sketch, in a 3d vector format. +.TP +.B export-mesh \-\-output [\-\-chord-tol ] +Exports a triangle mesh of solids in the sketch, with exact surfaces +being triangulated first. +.TP +.B export-surfaces \-\-output +Exports exact surfaces of solids in the sketch, if any. +.TP +.B regenerate [\-\-chord-tol ] +Reloads all imported files, regenerates the sketch, and saves it. +Note that, although this is not an export command, it uses absolute +chord tolerance, and can be used to prepare assemblies for export. +.PP +.SH FILE FORMATS +.TP +.B thumbnail: + PNG image (png) +.TP +.B export-view: + PDF file (pdf) + Encapsulated PostScript (eps, ps) + Scalable Vector Graphics (svg) + STEP file (step, stp) + DXF file (AutoCAD 2007) (dxf) + HPGL file (plt, hpgl) + G Code (ngc, txt) +.TP +.B export-wireframe: + STEP file (step, stp) + DXF file (AutoCAD 2007) (dxf) +.TP +.B export-mesh: + STL mesh (stl) + Wavefront OBJ mesh (obj) + Three.js-compatible mesh, with viewer (html) + Three.js-compatible mesh, mesh only (js) + Q3D Object file (q3do) + VRML text file (wrl) +.TP +.B export-surfaces: + STEP file (step, stp) +.PP +.SH "AUTHORS" +This manual page was written by Alexander Pozdnyakov , diff --git a/solvespace.1 b/solvespace.1 new file mode 100644 index 0000000..7885dc4 --- /dev/null +++ b/solvespace.1 @@ -0,0 +1,28 @@ +.\"Created with GNOME Manpages Editor Wizard +.\"http://sourceforge.net/projects/gmanedit2 +.TH solvespace 1 "August 15, 2016" "" "SOLVESPACE" + +.SH NAME +solvespace \- a parametric 3d CAD program + +.SH DESCRIPTION +.PP +.B modeling 3d parts - +draw with extrudes, revolves, helix creation, and Boolean (union / difference / intersection) operations +.PP +.B modeling 2d parts - +draw the part as a single section, and export DXF, PDF, SVG; use 3d assembly to verify fit +.PP +.B 3d-printed parts - +export the STL or other triangle mesh expected by most 3d printers +.PP +.B 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 +.PP +.B mechanism design - +use the constraint solver to simulate planar or spatial linkages, with pin, ball, or slide joints +.PP +.B plane and solid geometry - +replace hand-solved trigonometry and spreadsheets with a live dimensioned drawing +.PP + diff --git a/solvespace.install b/solvespace.install new file mode 100644 index 0000000..6819914 --- /dev/null +++ b/solvespace.install @@ -0,0 +1,3 @@ +usr/bin/solvespace +usr/bin/solvespace-cli +usr/share diff --git a/solvespace.links b/solvespace.links new file mode 100644 index 0000000..1b4d5d6 --- /dev/null +++ b/solvespace.links @@ -0,0 +1,2 @@ +usr/share/javascript/three/three.js usr/share/solvespace/threejs/three.js +usr/share/unifont/unifont.hex usr/share/solvespace/fonts/unifont.hex diff --git a/solvespace.lintian-overrides b/solvespace.lintian-overrides new file mode 100644 index 0000000..09bf699 --- /dev/null +++ b/solvespace.lintian-overrides @@ -0,0 +1,3 @@ +# These are actually resources used by the application +solvespace: package-contains-documentation-outside-usr-share-doc usr/share/solvespace/banner.txt +solvespace: package-contains-documentation-outside-usr-share-doc usr/share/solvespace/locales.txt diff --git a/solvespace.manpages b/solvespace.manpages new file mode 100644 index 0000000..46ff2a2 --- /dev/null +++ b/solvespace.manpages @@ -0,0 +1,3 @@ +debian/solvespace.1 +debian/solvespace-cli.1 + diff --git a/solvespace.sharedmimeinfo b/solvespace.sharedmimeinfo new file mode 100644 index 0000000..4f6e2cf --- /dev/null +++ b/solvespace.sharedmimeinfo @@ -0,0 +1,8 @@ + + + + SolveSpace sketch + + + + diff --git a/source/format b/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/source/options b/source/options new file mode 100644 index 0000000..a799080 --- /dev/null +++ b/source/options @@ -0,0 +1,5 @@ +## This file was written by cme command. +## You can run 'cme edit dpkg' to modify this file. +## You may also modify the content of this file with your favorite editor. + +tar-ignore=".git" diff --git a/tests/common b/tests/common new file mode 100644 index 0000000..df86ee9 --- /dev/null +++ b/tests/common @@ -0,0 +1,14 @@ + +get_all_files() { + find -name "*.slvs" +} + +get_files_with_surfaces() { + # Can't export the mesh/surfaces of a file with no 3d in it, just 2d + get_all_files | grep -E -v "(constraint)|(request)|(link)|(contour_area)" +} + +get_files_to_thumbnail() { + # Can't thumbnail files with embedded images: https://github.com/solvespace/solvespace/issues/905 + get_all_files | grep -v "image" +} diff --git a/tests/control b/tests/control new file mode 100644 index 0000000..180eaae --- /dev/null +++ b/tests/control @@ -0,0 +1,8 @@ +Tests: htmlmesh stlmesh surfaces +Restrictions: allow-stderr +Depends: solvespace, findutils, grep +Architecture: !s390x + +Tests: thumbnail view wireframe +Restrictions: allow-stderr +Depends: solvespace, findutils, grep diff --git a/tests/htmlmesh b/tests/htmlmesh new file mode 100755 index 0000000..f2a6323 --- /dev/null +++ b/tests/htmlmesh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e +set -x +. debian/tests/common +logname=$AUTOPKGTEST_TMP/html_mesh.txt +( + get_files_with_surfaces | while read fn; do + echo $fn + mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn) + solvespace-cli export-mesh --output $AUTOPKGTEST_TMP/%_mesh.html $fn + done +) 2>&1 | tee $logname + +# We don't care about self-intersecting errors. +! (grep "Error" $logname | grep -v "self-intersecting") diff --git a/tests/stlmesh b/tests/stlmesh new file mode 100755 index 0000000..eb3b218 --- /dev/null +++ b/tests/stlmesh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e +set -x +. debian/tests/common +logname=$AUTOPKGTEST_TMP/stl_mesh.txt +( + get_files_with_surfaces | while read fn; do + echo $fn + mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn) + solvespace-cli export-mesh --output $AUTOPKGTEST_TMP/%_mesh.stl $fn + done +) 2>&1 | tee $logname + +# We don't care about self-intersecting errors. +! (grep "Error" $logname | grep -v "self-intersecting") diff --git a/tests/surfaces b/tests/surfaces new file mode 100755 index 0000000..42c5bd1 --- /dev/null +++ b/tests/surfaces @@ -0,0 +1,14 @@ +#!/bin/sh +set -e +set -x +. debian/tests/common +logname=$AUTOPKGTEST_TMP/surfaces.txt +( + get_files_with_surfaces | while read fn; do + echo $fn + mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn) + solvespace-cli export-surfaces --output $AUTOPKGTEST_TMP/%_surfaces.step $fn + done +) 2>&1 | tee $logname + +! grep "Error" $logname diff --git a/tests/thumbnail b/tests/thumbnail new file mode 100755 index 0000000..7adf97e --- /dev/null +++ b/tests/thumbnail @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e +set -x +. debian/tests/common +logname=$AUTOPKGTEST_TMP/thumbnail.txt +( + get_files_to_thumbnail | while read fn; do + echo $fn + mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn) + solvespace-cli thumbnail --output $AUTOPKGTEST_TMP/%_thumb.png --size 48x48 --view isometric $fn + done +) 2>&1 | tee $logname + +# We don't care about self-intersecting errors. +! grep "Error" $logname diff --git a/tests/view b/tests/view new file mode 100755 index 0000000..7f709cc --- /dev/null +++ b/tests/view @@ -0,0 +1,14 @@ +#!/bin/sh +set -e +set -x +. debian/tests/common +logname=$AUTOPKGTEST_TMP/view.txt +( + get_all_files | while read fn; do + echo $fn + mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn) + solvespace-cli export-view --output $AUTOPKGTEST_TMP/%_view.pdf --view isometric $fn + done +) 2>&1 | tee $logname + +! grep "Error" $logname diff --git a/tests/wireframe b/tests/wireframe new file mode 100755 index 0000000..15d5205 --- /dev/null +++ b/tests/wireframe @@ -0,0 +1,14 @@ +#!/bin/sh +set -e +set -x +. debian/tests/common +logname=$AUTOPKGTEST_TMP/wireframe.txt +( + get_all_files | while read fn; do + echo $fn + mkdir -p $AUTOPKGTEST_TMP/$(dirname $fn) + solvespace-cli export-wireframe --output $AUTOPKGTEST_TMP/%_wireframe.dxf $fn + done +) 2>&1 | tee $logname + +! grep "Error" $logname diff --git a/upstream/metadata b/upstream/metadata new file mode 100644 index 0000000..4425fa5 --- /dev/null +++ b/upstream/metadata @@ -0,0 +1,4 @@ +Repository-Browse: https://github.com/solvespace/solvespace +Repository: https://github.com/solvespace/solvespace.git +Bug-Database: https://github.com/solvespace/solvespace/issues +Bug-Submit: https://github.com/solvespace/solvespace/issues/new diff --git a/watch b/watch new file mode 100644 index 0000000..88dc9e7 --- /dev/null +++ b/watch @@ -0,0 +1,8 @@ +version=4 +opts="\ + repacksuffix=+ds1,\ + uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|b|a)\d*)$/$1~$2/,\ + dversionmangle=s/@DEB_EXT@//" \ + https://github.com/solvespace/solvespace/releases \ + .*/@PACKAGE@-v?(\d\S*)@ARCHIVE_EXT@ + -- 2.30.2