Fix tab selection issues
Fix issue with save dialog when closing program UV Editor no longer updates when hidden, improving performance Fix animated texture preview in UV panel
This commit is contained in:
parent
35767f018f
commit
1b5bb9aba8
@ -1,5 +1,5 @@
|
||||
const electron = require('electron').remote;
|
||||
const {clipboard, shell, nativeImage, ipcRenderer} = require('electron');
|
||||
const {clipboard, shell, nativeImage, ipcRenderer, dialog} = require('electron');
|
||||
const app = electron.app;
|
||||
const fs = require('fs');
|
||||
const NodeBuffer = require('buffer');
|
||||
@ -29,32 +29,6 @@ const recent_projects = (function() {
|
||||
|
||||
app.setAppUserModelId('blockbench')
|
||||
|
||||
// Deprecated
|
||||
const ElecDialogs = {};
|
||||
if (electron.dialog.showMessageBoxSync) {
|
||||
ElecDialogs.showMessageBox = function(a, b, cb) {
|
||||
if (!cb) cb = b;
|
||||
var result = electron.dialog.showMessageBoxSync(a, b);
|
||||
if (typeof cb == 'function') cb(result);
|
||||
return result;
|
||||
}
|
||||
ElecDialogs.showSaveDialog = function(a, b, cb) {
|
||||
if (!cb) cb = b;
|
||||
var result = electron.dialog.showSaveDialogSync(a, b);
|
||||
if (typeof cb == 'function') cb(result);
|
||||
return result;
|
||||
}
|
||||
ElecDialogs.showOpenDialog = function(a, b, cb) {
|
||||
if (!cb) cb = b;
|
||||
var result = electron.dialog.showOpenDialogSync(a, b);
|
||||
if (typeof cb == 'function') cb(result);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
ElecDialogs.showMessageBox = electron.dialog.showMessageBox;
|
||||
ElecDialogs.showSaveDialog = electron.dialog.showSaveDialog;
|
||||
ElecDialogs.showOpenDialog = electron.dialog.showOpenDialog;
|
||||
}
|
||||
|
||||
function initializeDesktopApp() {
|
||||
|
||||
@ -275,17 +249,16 @@ function changeImageEditor(texture, from_settings) {
|
||||
}).show()
|
||||
}
|
||||
function selectImageEditorFile(texture) {
|
||||
ElecDialogs.showOpenDialog(currentwindow, {
|
||||
let filePaths = electron.dialog.showOpenDialogSync(currentwindow, {
|
||||
title: tl('message.image_editor.exe'),
|
||||
filters: [{name: 'Executable Program', extensions: ['exe', 'app']}]
|
||||
}, function(filePaths) {
|
||||
if (filePaths) {
|
||||
settings.image_editor.value = filePaths[0]
|
||||
if (texture) {
|
||||
texture.openEditor()
|
||||
}
|
||||
}
|
||||
})
|
||||
if (filePaths) {
|
||||
settings.image_editor.value = filePaths[0]
|
||||
if (texture) {
|
||||
texture.openEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
//Default Pack
|
||||
function openDefaultTexturePath() {
|
||||
@ -388,8 +361,18 @@ window.onbeforeunload = function (event) {
|
||||
}
|
||||
} catch (err) {}
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
showSaveDialog(true)
|
||||
setTimeout(async function() {
|
||||
let projects = ModelProject.all.slice();
|
||||
for (let project of projects) {
|
||||
let closed = await project.close();
|
||||
if (!closed) return false;
|
||||
}
|
||||
if (ModelProject.all.length === 0) {
|
||||
closeBlockbenchWindow()
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}, 2)
|
||||
event.returnValue = true;
|
||||
return true;
|
||||
@ -397,16 +380,18 @@ window.onbeforeunload = function (event) {
|
||||
}
|
||||
|
||||
function showSaveDialog(close) {
|
||||
|
||||
|
||||
/*
|
||||
if (Blockbench.hasFlag('allow_reload')) {
|
||||
close = false
|
||||
}
|
||||
var unsaved_textures = 0;
|
||||
Texture.all.forEach(function(t) {
|
||||
if (!t.saved) {
|
||||
unsaved_textures++;
|
||||
}
|
||||
})
|
||||
if ((window.Prop && Project.saved === false && (elements.length > 0 || Group.all.length > 0)) || unsaved_textures) {
|
||||
if (close) {
|
||||
unsaved_projects = ModelProject.all.find(project => {
|
||||
return !project.saved || project.textures.find(tex => !tex.saved)
|
||||
})
|
||||
}
|
||||
if (unsaved_changes || !close) {
|
||||
var answer = electron.dialog.showMessageBoxSync(currentwindow, {
|
||||
type: 'question',
|
||||
buttons: [tl('dialog.save'), tl('dialog.discard'), tl('dialog.cancel')],
|
||||
@ -433,7 +418,7 @@ function showSaveDialog(close) {
|
||||
closeBlockbenchWindow()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
function closeBlockbenchWindow() {
|
||||
window.onbeforeunload = null;
|
||||
|
@ -10,6 +10,7 @@ class Panel {
|
||||
this.selection_only = data.selection_only == true;
|
||||
this.condition = data.condition;
|
||||
this.onResize = data.onResize;
|
||||
this.onFold = data.onFold;
|
||||
this.folded = false;
|
||||
if (data.toolbars) {
|
||||
this.toolbars = data.toolbars;
|
||||
@ -156,10 +157,16 @@ class Panel {
|
||||
|
||||
Interface.Panels[this.id] = this;
|
||||
}
|
||||
isVisible() {
|
||||
return !this.folded && this.node.parentElement && this.node.parentElement.style.display !== 'none';
|
||||
}
|
||||
fold(state = !this.folded) {
|
||||
this.folded = !!state;
|
||||
$(this.handle).find('> .panel_folding_button > i').text(state ? 'expand_less' : 'expand_more');
|
||||
this.node.classList.toggle('folded', state);
|
||||
if (this.onFold) {
|
||||
this.onFold();
|
||||
}
|
||||
}
|
||||
moveTo(ref_panel, before) {
|
||||
let scope = this
|
||||
|
@ -165,7 +165,7 @@ class ModelProject {
|
||||
}
|
||||
}
|
||||
select() {
|
||||
if (this.selected) return;
|
||||
if (this === Project) return;
|
||||
if (Project) {
|
||||
Project.unselect()
|
||||
} else {
|
||||
@ -269,8 +269,34 @@ class ModelProject {
|
||||
Blockbench.dispatchEvent('unselect_project', {project: this});
|
||||
}
|
||||
async close(force) {
|
||||
let last_selected = Project;
|
||||
this.select();
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
if (force || showSaveDialog()) {
|
||||
function saveWarning() {
|
||||
if (Project.saved && !Project.textures.find(tex => !tex.saved)) {
|
||||
return true;
|
||||
} else {
|
||||
if (isApp) {
|
||||
var answer = electron.dialog.showMessageBoxSync(currentwindow, {
|
||||
type: 'question',
|
||||
buttons: [tl('dialog.save'), tl('dialog.discard'), tl('dialog.cancel')],
|
||||
title: 'Blockbench',
|
||||
message: tl('message.close_warning.message'),
|
||||
noLink: true
|
||||
})
|
||||
if (answer === 0) {
|
||||
BarItems.save_project.trigger();
|
||||
}
|
||||
return answer !== 2;
|
||||
} else {
|
||||
var answer = confirm(tl('message.close_warning.web'))
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (force || saveWarning()) {
|
||||
if (isApp) await updateRecentProjectThumbnail();
|
||||
|
||||
Blockbench.dispatchEvent('close_project');
|
||||
@ -278,12 +304,15 @@ class ModelProject {
|
||||
this.unselect();
|
||||
Texture.all.forEach(tex => tex.stopWatcher());
|
||||
|
||||
let index = ModelProject.all.indexOf(this);
|
||||
ModelProject.all.remove(this);
|
||||
delete ProjectData[this.uuid];
|
||||
Project = 0;
|
||||
|
||||
if (ModelProject.all.length) {
|
||||
ModelProject.all[0].select();
|
||||
if (last_selected !== this) {
|
||||
last_selected.select();
|
||||
} else if (ModelProject.all.length) {
|
||||
ModelProject.all[Math.clamp(index, 0, ModelProject.all.length-1)].select();
|
||||
} else {
|
||||
Interface.tab_bar.new_tab.visible = true;
|
||||
Interface.tab_bar.new_tab.select();
|
||||
@ -451,8 +480,8 @@ onVueSetup(() => {
|
||||
close: () => {
|
||||
if (ModelProject.all.length) {
|
||||
Interface.tab_bar.new_tab.visible = false;
|
||||
let project = Project.all.find(project => project.uuid == Interface.tab_bar.last_opened_project) ||
|
||||
Project.all.last();
|
||||
let project = ModelProject.all.find(project => project.uuid == Interface.tab_bar.last_opened_project) ||
|
||||
ModelProject.all.last();
|
||||
if (project) project.select();
|
||||
} else {
|
||||
window.close();
|
||||
|
@ -442,13 +442,13 @@ class Cube extends OutlinerElement {
|
||||
}
|
||||
transferOrigin(origin, update = true) {
|
||||
if (!this.mesh) return;
|
||||
var q = new THREE.Quaternion().copy(this.mesh.quaternion)
|
||||
var shift = new THREE.Vector3(
|
||||
var q = Reusable.quat1.copy(this.mesh.quaternion)
|
||||
var shift = Reusable.vec1.set(
|
||||
this.origin[0] - origin[0],
|
||||
this.origin[1] - origin[1],
|
||||
this.origin[2] - origin[2],
|
||||
)
|
||||
var dq = new THREE.Vector3().copy(shift)
|
||||
var dq = Reusable.vec2.copy(shift)
|
||||
dq.applyQuaternion(q)
|
||||
shift.sub(dq)
|
||||
shift.applyQuaternion(q.invert())
|
||||
@ -463,7 +463,7 @@ class Cube extends OutlinerElement {
|
||||
}
|
||||
getWorldCenter() {
|
||||
var m = this.mesh;
|
||||
var pos = new THREE.Vector3(
|
||||
var pos = Reusable.vec1.set(
|
||||
this.from[0] + this.size(0)/2,
|
||||
this.from[1] + this.size(1)/2,
|
||||
this.from[2] + this.size(2)/2
|
||||
@ -473,9 +473,9 @@ class Cube extends OutlinerElement {
|
||||
pos.z -= this.origin[2]
|
||||
|
||||
if (m) {
|
||||
var r = m.getWorldQuaternion(new THREE.Quaternion())
|
||||
var r = m.getWorldQuaternion(Reusable.quat1)
|
||||
pos.applyQuaternion(r)
|
||||
pos.add(THREE.fastWorldPosition(m, new THREE.Vector3()))
|
||||
pos.add(THREE.fastWorldPosition(m, Reusable.vec2))
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
@ -64,15 +64,15 @@ class Locator extends OutlinerElement {
|
||||
return this;
|
||||
}
|
||||
getWorldCenter() {
|
||||
var pos = new THREE.Vector3();
|
||||
var q = new THREE.Quaternion();
|
||||
var pos = Reusable.vec1.set(0, 0, 0);
|
||||
var q = Reusable.quat1.set(0, 0, 0, 1);
|
||||
if (this.parent instanceof Group) {
|
||||
THREE.fastWorldPosition(this.parent.mesh, pos);
|
||||
this.parent.mesh.getWorldQuaternion(q);
|
||||
var offset2 = new THREE.Vector3().fromArray(this.parent.origin).applyQuaternion(q);
|
||||
var offset2 = Reusable.vec2.fromArray(this.parent.origin).applyQuaternion(q);
|
||||
pos.sub(offset2);
|
||||
}
|
||||
var offset = new THREE.Vector3().fromArray(this.from).applyQuaternion(q);
|
||||
var offset = Reusable.vec3.fromArray(this.from).applyQuaternion(q);
|
||||
pos.add(offset);
|
||||
|
||||
return pos;
|
||||
|
@ -159,7 +159,7 @@ class Mesh extends OutlinerElement {
|
||||
}
|
||||
getWorldCenter(ignore_selected_vertices) {
|
||||
let m = this.mesh;
|
||||
let pos = new THREE.Vector3()
|
||||
let pos = Reusable.vec1.set(0, 0, 0);
|
||||
let vertice_count = 0;
|
||||
|
||||
for (let key in this.vertices) {
|
||||
@ -176,9 +176,9 @@ class Mesh extends OutlinerElement {
|
||||
pos.z /= vertice_count;
|
||||
|
||||
if (m) {
|
||||
let r = m.getWorldQuaternion(new THREE.Quaternion());
|
||||
let r = m.getWorldQuaternion(Reusable.quat1);
|
||||
pos.applyQuaternion(r);
|
||||
pos.add(THREE.fastWorldPosition(m, new THREE.Vector3()));
|
||||
pos.add(THREE.fastWorldPosition(m, Reusable.vec2));
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@ -704,21 +704,25 @@ new NodePreviewController(Mesh, {
|
||||
},
|
||||
updateSelection(element) {
|
||||
NodePreviewController.prototype.updateSelection(element);
|
||||
|
||||
|
||||
let mesh = element.mesh;
|
||||
let colors = [];
|
||||
let line_colors = [];
|
||||
|
||||
for (let key in element.vertices) {
|
||||
let color;
|
||||
if (Project.selected_vertices[element.uuid] && Project.selected_vertices[element.uuid].includes(key)) {
|
||||
color = gizmo_colors.outline;
|
||||
} else {
|
||||
color = gizmo_colors.grid;
|
||||
if (BarItems.selection_mode.value == 'vertex') {
|
||||
let colors = [];
|
||||
for (let key in element.vertices) {
|
||||
let color;
|
||||
if (Project.selected_vertices[element.uuid] && Project.selected_vertices[element.uuid].includes(key)) {
|
||||
color = gizmo_colors.outline;
|
||||
} else {
|
||||
color = gizmo_colors.grid;
|
||||
}
|
||||
colors.push(color.r, color.g, color.b);
|
||||
}
|
||||
colors.push(color.r, color.g, color.b);
|
||||
mesh.vertex_points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
||||
mesh.outline.geometry.needsUpdate = true;
|
||||
}
|
||||
|
||||
let line_colors = [];
|
||||
mesh.outline.vertex_order.forEach(key => {
|
||||
let color;
|
||||
if (!Modes.edit || BarItems.selection_mode.value == 'object' || (Project.selected_vertices[element.uuid] && Project.selected_vertices[element.uuid].includes(key))) {
|
||||
@ -728,10 +732,9 @@ new NodePreviewController(Mesh, {
|
||||
}
|
||||
line_colors.push(color.r, color.g, color.b);
|
||||
})
|
||||
|
||||
mesh.vertex_points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
||||
mesh.outline.geometry.setAttribute('color', new THREE.Float32BufferAttribute(line_colors, 3));
|
||||
mesh.outline.geometry.needsUpdate = true
|
||||
mesh.outline.geometry.needsUpdate = true;
|
||||
|
||||
mesh.vertex_points.visible = Mode.selected.id == 'edit' && BarItems.selection_mode.value == 'vertex';
|
||||
},
|
||||
updateHighlight(element, hover_cube, force_off) {
|
||||
@ -1664,7 +1667,7 @@ BARS.defineActions(function() {
|
||||
vector2.fromArray(f.vertex_normals[0]);
|
||||
let angle = vector1.angleTo(vector2);
|
||||
if (angle > Math.PI/2) {
|
||||
new_face.invert();
|
||||
face.invert();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,15 +60,15 @@ class NullObject extends OutlinerElement {
|
||||
return this;
|
||||
}
|
||||
getWorldCenter() {
|
||||
var pos = new THREE.Vector3();
|
||||
var q = new THREE.Quaternion();
|
||||
var pos = Reusable.vec1.set(0, 0, 0);
|
||||
var q = Reusable.quat1.set(0, 0, 0, 1);
|
||||
if (this.parent instanceof Group) {
|
||||
THREE.fastWorldPosition(this.parent.mesh, pos);
|
||||
this.parent.mesh.getWorldQuaternion(q);
|
||||
var offset2 = new THREE.Vector3().fromArray(this.parent.origin).applyQuaternion(q);
|
||||
var offset2 = Reusable.vec2.fromArray(this.parent.origin).applyQuaternion(q);
|
||||
pos.sub(offset2);
|
||||
}
|
||||
var offset = new THREE.Vector3().fromArray(this.from).applyQuaternion(q);
|
||||
var offset = Reusable.vec3.fromArray(this.from).applyQuaternion(q);
|
||||
pos.add(offset);
|
||||
|
||||
return pos;
|
||||
|
@ -465,11 +465,11 @@ class OutlinerElement extends OutlinerNode {
|
||||
s.selected = false;
|
||||
})
|
||||
Blockbench.dispatchEvent('added_to_selection', {added: just_selected})
|
||||
updateSelection()
|
||||
TickUpdates.selection = true;
|
||||
return this;
|
||||
}
|
||||
selectLow() {
|
||||
selected.safePush(this);
|
||||
Outliner.selected.safePush(this);
|
||||
this.constructor.selected.safePush(this)
|
||||
this.selected = true;
|
||||
TickUpdates.selection = true;
|
||||
|
@ -14,12 +14,12 @@ class TextureMesh extends OutlinerElement {
|
||||
}
|
||||
getWorldCenter() {
|
||||
let m = this.mesh;
|
||||
let pos = new THREE.Vector3().fromArray(this.local_pivot);
|
||||
let pos = Reusable.vec1.fromArray(this.local_pivot);
|
||||
|
||||
if (m) {
|
||||
let r = m.getWorldQuaternion(new THREE.Quaternion());
|
||||
let r = m.getWorldQuaternion(Reusable.quat1);
|
||||
pos.applyQuaternion(r);
|
||||
pos.add(THREE.fastWorldPosition(m, new THREE.Vector3()));
|
||||
pos.add(THREE.fastWorldPosition(m, Reusable.vec2));
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
@ -18,6 +18,21 @@ function getRescalingFactor(angle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const Reusable = {
|
||||
vec1: new THREE.Vector3(),
|
||||
vec2: new THREE.Vector3(),
|
||||
vec3: new THREE.Vector3(),
|
||||
vec4: new THREE.Vector3(),
|
||||
vec5: new THREE.Vector3(),
|
||||
vec6: new THREE.Vector3(),
|
||||
vec7: new THREE.Vector3(),
|
||||
vec8: new THREE.Vector3(),
|
||||
|
||||
quat1: new THREE.Quaternion(),
|
||||
quat2: new THREE.Quaternion(),
|
||||
}
|
||||
|
||||
const Canvas = {
|
||||
outlineMaterial: new THREE.LineBasicMaterial({
|
||||
linewidth: 2,
|
||||
|
@ -654,10 +654,7 @@ const UVEditor = {
|
||||
this.message('uv_editor.turned');
|
||||
this.loadData();
|
||||
},
|
||||
setAutoSize(event) {
|
||||
var scope = this;
|
||||
var top2, left2;
|
||||
|
||||
setAutoSize(event) {
|
||||
let vec1 = new THREE.Vector3(),
|
||||
vec2 = new THREE.Vector3(),
|
||||
vec3 = new THREE.Vector3(),
|
||||
@ -666,8 +663,9 @@ const UVEditor = {
|
||||
plane = new THREE.Plane();
|
||||
|
||||
this.getMappableElements().forEach(obj => {
|
||||
var top2, left2;
|
||||
if (obj instanceof Cube) {
|
||||
scope.getFaces(obj, event).forEach(function(side) {
|
||||
this.getFaces(obj, event).forEach(function(side) {
|
||||
let face = obj.faces[side];
|
||||
let mirror_x = face.uv[0] > face.uv[2];
|
||||
let mirror_y = face.uv[1] > face.uv[3];
|
||||
@ -686,8 +684,8 @@ const UVEditor = {
|
||||
if (face.rotation % 180) {
|
||||
[left2, top2] = [top2, left2];
|
||||
}
|
||||
left2 *= scope.getResolution(0, face) / Project.texture_width;
|
||||
top2 *= scope.getResolution(1, face) / Project.texture_height;
|
||||
left2 *= this.getResolution(0, face) / Project.texture_width;
|
||||
top2 *= this.getResolution(1, face) / Project.texture_height;
|
||||
face.uv_size = [left2, top2];
|
||||
if (mirror_x) [face.uv[0], face.uv[2]] = [face.uv[2], face.uv[0]];
|
||||
if (mirror_y) [face.uv[1], face.uv[3]] = [face.uv[3], face.uv[1]];
|
||||
@ -695,7 +693,7 @@ const UVEditor = {
|
||||
obj.autouv = 0
|
||||
|
||||
} else if (obj instanceof Mesh) {
|
||||
scope.getFaces(obj, event).forEach(fkey => {
|
||||
this.getFaces(obj, event).forEach(fkey => {
|
||||
let face = obj.faces[fkey];
|
||||
let vertex_uvs = {};
|
||||
let uv_center = [0, 0];
|
||||
@ -1475,11 +1473,16 @@ Interface.definePanels(function() {
|
||||
bottom: Toolbars.UVEditor
|
||||
},
|
||||
onResize: function() {
|
||||
UVEditor.vue.updateSize()
|
||||
UVEditor.vue.updateSize();
|
||||
UVEditor.vue.hidden = !this.isVisible();
|
||||
},
|
||||
onFold: function() {
|
||||
UVEditor.vue.hidden = !this.isVisible();
|
||||
},
|
||||
component: {
|
||||
data() {return {
|
||||
mode: 'uv',
|
||||
hidden: false,
|
||||
box_uv: false,
|
||||
width: 320,
|
||||
height: 320,
|
||||
@ -1953,6 +1956,7 @@ Interface.definePanels(function() {
|
||||
@mouseleave="if (mode == 'paint') mouse_coords.x = -1"
|
||||
class="checkerboard_target"
|
||||
ref="viewport"
|
||||
v-show="!hidden"
|
||||
:style="{width: (width+8) + 'px', height: (height+8) + 'px', overflowX: (zoom > 1) ? 'scroll' : 'hidden', overflowY: (inner_height > height) ? 'scroll' : 'hidden'}"
|
||||
>
|
||||
|
||||
@ -2030,8 +2034,8 @@ Interface.definePanels(function() {
|
||||
|
||||
<div id="uv_brush_outline" v-if="mode == 'paint' && mouse_coords.x >= 0" :style="getBrushOutlineStyle()"></div>
|
||||
|
||||
<img style="object-fit: cover; object-position: 0px 0px;" v-if="texture && texture.error != 1" :src="texture.source">
|
||||
<img style="object-fit: cover; object-position: 0px 0px; opacity: 0.02; mix-blend-mode: screen;" v-if="texture == 0 && !box_uv" src="./assets/missing_blend.png">
|
||||
<img style="object-fit: cover;" :style="{objectPosition: \`0 -\${texture.currentFrame * inner_height}px\`}" v-if="texture && texture.error != 1" :src="texture.source">
|
||||
<img style="object-fit: cover; opacity: 0.02; mix-blend-mode: screen;" v-if="texture == 0 && !box_uv" src="./assets/missing_blend.png">
|
||||
</div>
|
||||
|
||||
<div class="uv_transparent_face" v-else-if="selected_faces.length">${tl('uv_editor.transparent_face')}</div>
|
||||
|
20
js/web.js
20
js/web.js
@ -35,28 +35,16 @@ function loadInfoFromURL() {
|
||||
|
||||
//Misc
|
||||
window.onbeforeunload = function() {
|
||||
if (Project.saved === false && elements.length > 0) {
|
||||
let unsaved_projects = ModelProject.all.find(project => {
|
||||
return !project.saved || project.textures.find(tex => !tex.saved)
|
||||
})
|
||||
if (unsaved_projects) {
|
||||
return 'Unsaved Changes';
|
||||
} else {
|
||||
Blockbench.dispatchEvent('before_closing')
|
||||
if (Project.EditSession) Project.EditSession.quit()
|
||||
}
|
||||
}
|
||||
function showSaveDialog(close) {
|
||||
var unsaved_textures = 0;
|
||||
Texture.all.forEach(function(t) {
|
||||
if (!t.saved) {
|
||||
unsaved_textures++;
|
||||
}
|
||||
})
|
||||
if ((Project.saved === false && elements.length > 0) || unsaved_textures) {
|
||||
|
||||
var answer = confirm(tl('message.close_warning.web'))
|
||||
return answer;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function setupMobilePanelSelector() {
|
||||
if (Blockbench.isMobile) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user