diff --git a/bindings/wasm/examples/editor.css b/bindings/wasm/examples/editor.css index 1fddb7a71..7b3a1e059 100644 --- a/bindings/wasm/examples/editor.css +++ b/bindings/wasm/examples/editor.css @@ -130,18 +130,14 @@ model-viewer { .header .margin { font-size: 16px; - margin: 1em; -} - -#file { - width: 250px; + margin: 1em 0.5em; } .dropdown { display: none; position: absolute; z-index: 1; - width: 250px; + width: 100%; max-height: 80vh; overflow-y: auto; } @@ -150,6 +146,10 @@ model-viewer { display: block; } +.hide { + display: none; +} + .uparrow { display: inline-block; position: relative; @@ -174,6 +174,7 @@ model-viewer { position: absolute; width: 36px; top: 0px; + right: 0px; background-size: 20px; background-repeat: no-repeat; background-position: center; @@ -193,7 +194,6 @@ model-viewer { .trash { background-image: url(/icons/trash.png); - right: 0px; } .icon:hover { @@ -212,6 +212,15 @@ model-viewer { background-color: rgb(255, 177, 177); } +#file-margin { + position: relative; + width: 250px; +} + +#save { + width: 125px; +} + @media only screen and (max-width: 600px) { .container { flex-direction: column; @@ -220,5 +229,31 @@ model-viewer { .col { width: 100%; + height: 50%; + } + + #file-margin { + width: calc(100% - 32px); + } + + p { + margin: .2em 1em; + text-align: center; } -} \ No newline at end of file + + .header .margin { + margin: 0.2em 16px; + } + + #button-container { + flex-direction: row; + margin-left: 8px; + margin-right: 8px; + width: calc(100% - 16px); + } + + #button-container .margin { + width: calc(50% - 16px); + margin: 8px; + } +} diff --git a/bindings/wasm/examples/editor.js b/bindings/wasm/examples/editor.js index 224965561..93efb21ad 100644 --- a/bindings/wasm/examples/editor.js +++ b/bindings/wasm/examples/editor.js @@ -26,20 +26,31 @@ let editor = undefined; // File UI ------------------------------------------------------------ const fileButton = document.querySelector('#file'); -const currentElement = document.querySelector('#current'); -const arrow = document.querySelector('.uparrow'); -const dropdown = document.querySelector('.dropdown'); +const currentFileElement = document.querySelector('#current'); +const fileArrow = document.querySelector('#file .uparrow'); +const fileDropdown = document.querySelector('#fileDropdown'); +const saveContainer = document.querySelector('#save'); +const saveDropdown = document.querySelector('#saveDropdown'); +const saveArrow = document.querySelector('#save .uparrow'); const hideDropdown = function() { - dropdown.classList.remove('show'); - arrow.classList.remove('down'); + fileDropdown.classList.remove('show'); + saveDropdown.classList.remove('show'); + fileArrow.classList.remove('down'); + saveArrow.classList.remove('down'); }; -const toggleDropdown = function(event) { +const toggleFileDropdown = function(event) { event.stopPropagation(); - dropdown.classList.toggle('show'); - arrow.classList.toggle('down'); + fileDropdown.classList.toggle('show'); + fileArrow.classList.toggle('down'); }; -fileButton.onclick = toggleDropdown; +const toggleSaveDropdown = function(event) { + event.stopPropagation(); + saveDropdown.classList.toggle('show'); + saveArrow.classList.toggle('down'); +}; +fileButton.onclick = toggleFileDropdown; +saveArrow.parentElement.onclick = toggleSaveDropdown; document.body.onclick = hideDropdown; const prefix = 'ManifoldCAD'; @@ -62,7 +73,7 @@ function nthKey(n) { function saveCurrent() { if (editor) { - const currentName = currentElement.textContent; + const currentName = currentFileElement.textContent; if (!exampleFunctions.get(currentName)) { setScript(currentName, editor.getValue()); } @@ -77,7 +88,7 @@ let isExample = true; function switchTo(scriptName) { if (editor) { switching = true; - currentElement.textContent = scriptName; + currentFileElement.textContent = scriptName; setScript('currentName', scriptName); const code = exampleFunctions.get(scriptName) ?? getScript(scriptName) ?? ''; @@ -148,8 +159,8 @@ function addEdit(button) { if (!input) return; const newName = uniqueName(input); label.textContent = newName; - if (currentElement.textContent == oldName) { - currentElement.textContent = newName; + if (currentFileElement.textContent == oldName) { + currentFileElement.textContent = newName; } removeScript(oldName); setScript(newName, code); @@ -182,7 +193,7 @@ function addEdit(button) { }, {once: true}); } else if (performance.now() - lastClick > 500) { removeScript(label.textContent); - if (currentElement.textContent == label.textContent) { + if (currentFileElement.textContent == label.textContent) { switchTo('Intro'); } const container = button.parentElement; @@ -269,10 +280,10 @@ require(['vs/editor/editor.main'], async function() { for (const [name] of exampleFunctions) { const button = createDropdownItem(name); - dropdown.appendChild(button.parentElement); + fileDropdown.appendChild(button.parentElement); } - let currentName = currentElement.textContent; + let currentName = currentFileElement.textContent; for (let i = 0; i < window.localStorage.length; i++) { const key = nthKey(i); @@ -347,8 +358,10 @@ function finishRun() { } const mv = document.querySelector('model-viewer'); -let glbURL = null; -let threeMFURL = null; +const output = { + glbURL: null, + threeMFURL: null +}; let manifoldWorker = null; function createWorker() { @@ -371,16 +384,16 @@ function createWorker() { finishRun(); runButton.disabled = true; - if (threeMFURL != undefined) { - URL.revokeObjectURL(threeMFURL); - threeMFURL = undefined; + if (output.threeMFURL != null) { + URL.revokeObjectURL(output.threeMFURL); + output.threeMFURL = null; } - URL.revokeObjectURL(glbURL); - glbURL = e.data.glbURL; - threeMFURL = e.data.threeMFURL; - threemfButton.disabled = threeMFURL == undefined; - mv.src = glbURL; - if (glbURL == null) { + URL.revokeObjectURL(output.glbURL); + output.glbURL = e.data.glbURL; + output.threeMFURL = e.data.threeMFURL; + threemfButton.disabled = output.threeMFURL == null; + mv.src = output.glbURL; + if (output.glbURL == null) { mv.showPoster(); poster.textContent = 'Error'; createWorker(); @@ -418,18 +431,24 @@ runButton.onclick = function() { } }; +function clickSave(saveButton, filename, outputName) { + const container = saveButton.parentElement; + return () => { + const oldSave = saveContainer.firstElementChild; + if (oldSave !== container) { + saveDropdown.insertBefore(oldSave, saveDropdown.firstElementChild); + saveContainer.insertBefore(container, saveDropdown); + container.appendChild(saveArrow.parentElement); + } + const link = document.createElement('a'); + link.download = filename; + link.href = output[outputName]; + link.click(); + }; +} + const glbButton = document.querySelector('#glb'); -glbButton.onclick = function() { - const link = document.createElement('a'); - link.download = 'manifold.glb'; - link.href = glbURL; - link.click(); -}; +glbButton.onclick = clickSave(glbButton, 'manifold.glb', 'glbURL'); const threemfButton = document.querySelector('#threemf'); -threemfButton.onclick = function() { - const link = document.createElement('a'); - link.download = 'manifold.3mf'; - link.href = threeMFURL; - link.click(); -}; +threemfButton.onclick = clickSave(threemfButton, 'manifold.3mf', 'threeMFURL'); diff --git a/bindings/wasm/examples/index.html b/bindings/wasm/examples/index.html index 74037e1db..20464c802 100644 --- a/bindings/wasm/examples/index.html +++ b/bindings/wasm/examples/index.html @@ -40,16 +40,27 @@

ManifoldCAD

-
- - - - - +
+ +
+
+ + +
+ +
+
diff --git a/src/polygon/src/polygon.cpp b/src/polygon/src/polygon.cpp index a2519c70b..b1961b2c7 100644 --- a/src/polygon/src/polygon.cpp +++ b/src/polygon/src/polygon.cpp @@ -20,7 +20,7 @@ #endif #include #include -#if !__APPLE__ +#if __has_include() #include #endif #include @@ -311,14 +311,7 @@ class Monotones { struct VertAdj; struct EdgePair; enum VertType { Start, WestSide, EastSide, Merge, End, Skip }; -#if __APPLE__ - typedef std::list::iterator VertItr; - typedef std::list::iterator PairItr; - - std::list monotones_; // sweep-line list of verts - std::list activePairs_; // west to east monotone edges - std::list inactivePairs_; // completed monotones -#else +#if __has_include() typedef std::pmr::list::iterator VertItr; typedef std::pmr::list::iterator PairItr; @@ -327,6 +320,13 @@ class Monotones { std::pmr::list monotones_{pa}; // sweep-line list of verts std::pmr::list activePairs_{pa}; // west to east monotone edges std::pmr::list inactivePairs_{pa}; // completed monotones +#else + typedef std::list::iterator VertItr; + typedef std::list::iterator PairItr; + + std::list monotones_; // sweep-line list of verts + std::list activePairs_; // west to east monotone edges + std::list inactivePairs_; // completed monotones #endif float precision_; // a triangle of this height or less is degenerate