def95852b5
Fix #1125 The Java Block/Item rotation limit is not enforced when pasting elements Remove menu option to set texture to transparent on mesh Face selection now validates face existance when selecting different elements
396 lines
11 KiB
JavaScript
396 lines
11 KiB
JavaScript
|
|
const Clipbench = {
|
|
elements: [],
|
|
types: {
|
|
text: 'text',
|
|
display_slot: 'display_slot',
|
|
keyframe: 'keyframe',
|
|
face: 'face',
|
|
mesh_selection: 'mesh_selection',
|
|
texture: 'texture',
|
|
outliner: 'outliner',
|
|
texture_selection: 'texture_selection',
|
|
},
|
|
type_icons: {
|
|
face: 'aspect_ratio',
|
|
mesh_selection: 'fa-gem',
|
|
outliner: 'fas.fa-cube',
|
|
},
|
|
getCopyType(mode, check) {
|
|
// mode: 1 = copy, 2 = paste
|
|
let p = Prop.active_panel;
|
|
let text;
|
|
if (!check) {
|
|
text = getFocusedTextInput() && window.getSelection()+'';
|
|
}
|
|
if (text) {
|
|
return Clipbench.types.text;
|
|
}
|
|
if (Painter.selection.canvas && Toolbox.selected.id == 'copy_paste_tool') {
|
|
return Clipbench.types.texture_selection;
|
|
}
|
|
if (display_mode) {
|
|
return Clipbench.types.display_slot
|
|
}
|
|
if (Animator.open && Timeline.animators.length && (Timeline.selected.length || mode === 2) && ['keyframe', 'timeline', 'preview'].includes(p)) {
|
|
return Clipbench.types.keyframe
|
|
}
|
|
if (Modes.edit && p == 'preview' && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length && (mode !== 2 || Clipbench.vertices)) {
|
|
return Clipbench.types.mesh_selection;
|
|
}
|
|
if (mode == 2 && Modes.edit && Format.meshes && Clipbench.last_copied == 'mesh_selection' && (p == 'preview' || p == 'outliner')) {
|
|
return Clipbench.types.mesh_selection;
|
|
}
|
|
if ((p == 'uv' || p == 'preview') && Modes.edit) {
|
|
return Clipbench.types.face;
|
|
}
|
|
if (p == 'textures' && (Texture.selected || mode === 2)) {
|
|
return Clipbench.types.texture;
|
|
}
|
|
if (p == 'outliner' && Modes.edit) {
|
|
return Clipbench.types.outliner;
|
|
}
|
|
},
|
|
async getPasteType() {
|
|
let p = Prop.active_panel;
|
|
if (getFocusedTextInput()) {
|
|
return Clipbench.types.text;
|
|
}
|
|
if (Painter.selection.canvas && Toolbox.selected.id == 'copy_paste_tool') {
|
|
return Clipbench.types.texture_selection;
|
|
}
|
|
if (display_mode) {
|
|
return Clipbench.types.display_slot
|
|
}
|
|
if (Animator.open && Timeline.animators.length && ['keyframe', 'timeline', 'preview'].includes(p)) {
|
|
return Clipbench.types.keyframe
|
|
}
|
|
if (Modes.edit && p == 'preview') {
|
|
let options = [];
|
|
if (Clipbench.elements.length || Clipbench.group) {
|
|
options.push(Clipbench.types.outliner);
|
|
}
|
|
if (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length && Clipbench.vertices) {
|
|
options.push(Clipbench.types.mesh_selection);
|
|
}
|
|
if (UVEditor.getMappableElements().length && UVEditor.clipboard.length) {
|
|
options.push(Clipbench.types.face);
|
|
}
|
|
if (options.length > 1) {
|
|
return await new Promise((resolve, reject) => {
|
|
new Menu(options.map(option => {
|
|
return {
|
|
id: option,
|
|
name: tl(`menu.paste.${option}`),
|
|
icon: Clipbench.type_icons[option],
|
|
click() {
|
|
resolve(option);
|
|
}
|
|
}
|
|
})).show('mouse');
|
|
})
|
|
} else {
|
|
return options[0]
|
|
}
|
|
}
|
|
if (p == 'uv' && Modes.edit && UVEditor.clipboard.length) {
|
|
return Clipbench.types.face;
|
|
}
|
|
if (p == 'textures') {
|
|
return Clipbench.types.texture;
|
|
}
|
|
if (p == 'outliner' && Modes.edit) {
|
|
return Clipbench.types.outliner;
|
|
}
|
|
},
|
|
copy(event, cut) {
|
|
let copy_type = Clipbench.getCopyType(1);
|
|
Clipbench.last_copied = copy_type;
|
|
switch (copy_type) {
|
|
case 'text':
|
|
Clipbench.setText(window.getSelection()+'');
|
|
break;
|
|
case 'display_slot':
|
|
DisplayMode.copy();
|
|
break;
|
|
case 'keyframe':
|
|
if (Timeline.selected.length) {
|
|
Clipbench.setKeyframes();
|
|
if (cut) {
|
|
BarItems.delete.trigger();
|
|
}
|
|
}
|
|
break;
|
|
case 'face':
|
|
UVEditor.copy(event);
|
|
break;
|
|
case 'mesh_selection':
|
|
UVEditor.copy(event);
|
|
Clipbench.setMeshSelection(Mesh.selected[0], event);
|
|
break;
|
|
case 'texture':
|
|
Clipbench.setTexture(Texture.selected);
|
|
if (cut) {
|
|
BarItems.delete.trigger();
|
|
}
|
|
break;
|
|
}
|
|
if (copy_type == 'outliner' || (copy_type == 'face' && Prop.active_panel == 'preview')) {
|
|
Clipbench.setElements();
|
|
Clipbench.setGroup();
|
|
if (Group.selected) {
|
|
Clipbench.setGroup(Group.selected);
|
|
} else {
|
|
Clipbench.setElements(selected);
|
|
}
|
|
if (cut) {
|
|
BarItems.delete.trigger();
|
|
}
|
|
}
|
|
},
|
|
async paste(event) {
|
|
switch (await Clipbench.getPasteType()) {
|
|
case 'text':
|
|
Clipbench.setText(window.getSelection()+'');
|
|
break;
|
|
case 'texture_selection':
|
|
UVEditor.addPastingOverlay();
|
|
break;
|
|
case 'display_slot':
|
|
DisplayMode.paste();
|
|
break;
|
|
case 'keyframe':
|
|
Clipbench.pasteKeyframes()
|
|
break;
|
|
case 'face':
|
|
UVEditor.paste(event);
|
|
break;
|
|
case 'mesh_selection':
|
|
Clipbench.pasteMeshSelection();
|
|
break;
|
|
case 'texture':
|
|
Clipbench.pasteTextures();
|
|
break;
|
|
case 'outliner':
|
|
Clipbench.pasteOutliner(event);
|
|
break;
|
|
}
|
|
},
|
|
setGroup(group) {
|
|
if (!group) {
|
|
Clipbench.group = undefined
|
|
return;
|
|
}
|
|
Clipbench.group = group.getSaveCopy()
|
|
if (isApp) {
|
|
clipboard.writeHTML(JSON.stringify({type: 'group', content: Clipbench.group}))
|
|
}
|
|
},
|
|
setElements(arr) {
|
|
if (!arr) {
|
|
Clipbench.elements = []
|
|
return;
|
|
}
|
|
arr.forEach(function(element) {
|
|
Clipbench.elements.push(element.getSaveCopy())
|
|
})
|
|
if (isApp) {
|
|
clipboard.writeHTML(JSON.stringify({type: 'elements', content: Clipbench.elements}))
|
|
}
|
|
},
|
|
setText(text) {
|
|
if (isApp) {
|
|
clipboard.writeText(text)
|
|
} else if (navigator.clipboard) {
|
|
navigator.clipboard.writeText(text);
|
|
} else {
|
|
document.execCommand('copy')
|
|
}
|
|
},
|
|
setMeshSelection(mesh) {
|
|
this.vertices = {};
|
|
this.faces = {};
|
|
mesh.getSelectedVertices().forEach(vkey => {
|
|
this.vertices[vkey] = mesh.vertices[vkey].slice();
|
|
})
|
|
for (let fkey in mesh.faces) {
|
|
let face = mesh.faces[fkey];
|
|
if (face.isSelected()) {
|
|
this.faces[fkey] = new MeshFace(null, face);
|
|
}
|
|
}
|
|
},
|
|
pasteMeshSelection() {
|
|
let elements = Mesh.selected.slice();
|
|
Undo.initEdit({elements});
|
|
let new_mesh;
|
|
if (!elements.length) {
|
|
new_mesh = new Mesh({name: 'pasted', vertices: []});
|
|
elements.push(new_mesh);
|
|
}
|
|
elements.forEach(mesh => {
|
|
let old_vertices = Object.keys(this.vertices);
|
|
let vertices_positions = old_vertices.map(vkey => this.vertices[vkey]);
|
|
let new_vertices = mesh.addVertices(...vertices_positions);
|
|
|
|
for (let old_fkey in this.faces) {
|
|
let old_face = this.faces[old_fkey];
|
|
let new_face = new MeshFace(mesh, old_face);
|
|
let new_face_vertices = new_face.vertices.map(old_vkey => {
|
|
let new_vkey = new_vertices[old_vertices.indexOf(old_vkey)];
|
|
new_face.uv[new_vkey] = new_face.uv[old_vkey];
|
|
delete new_face.uv[old_vkey];
|
|
return new_vkey;
|
|
})
|
|
new_face.vertices.replace(new_face_vertices);
|
|
mesh.addFaces(new_face);
|
|
}
|
|
mesh.getSelectedVertices(true).replace(new_vertices);
|
|
})
|
|
if (new_mesh) {
|
|
new_mesh.init().select();
|
|
}
|
|
Undo.finishEdit('Paste mesh selection');
|
|
Canvas.updateView({elements: Mesh.selected, selection: true})
|
|
},
|
|
pasteOutliner(event) {
|
|
Undo.initEdit({outliner: true, elements: [], selection: true});
|
|
//Group
|
|
var target = 'root'
|
|
if (Group.selected) {
|
|
target = Group.selected
|
|
Group.selected.isOpen = true
|
|
} else if (selected[0]) {
|
|
target = selected[0]
|
|
}
|
|
selected.length = 0
|
|
if (isApp) {
|
|
var raw = clipboard.readHTML()
|
|
try {
|
|
var data = JSON.parse(raw)
|
|
if (data.type === 'elements' && data.content) {
|
|
Clipbench.group = undefined;
|
|
Clipbench.elements = data.content;
|
|
} else if (data.type === 'group' && data.content) {
|
|
Clipbench.group = data.content;
|
|
Clipbench.elements = [];
|
|
}
|
|
} catch (err) {}
|
|
}
|
|
if (Clipbench.group) {
|
|
function iterate(obj, parent) {
|
|
if (obj.children) {
|
|
var copy = new Group(obj).addTo(parent).init()
|
|
copy.createUniqueName();
|
|
|
|
if (obj.children && obj.children.length) {
|
|
obj.children.forEach((child) => {
|
|
iterate(child, copy)
|
|
})
|
|
}
|
|
} else if (OutlinerElement.isTypePermitted(obj.type)) {
|
|
var el = OutlinerElement.fromSave(obj).addTo(parent).selectLow();
|
|
el.createUniqueName();
|
|
el.preview_controller.updateTransform(el);
|
|
}
|
|
}
|
|
iterate(Clipbench.group, target)
|
|
updateSelection()
|
|
|
|
} else if (Clipbench.elements && Clipbench.elements.length) {
|
|
let elements = [];
|
|
Clipbench.elements.forEach(function(obj) {
|
|
if (!OutlinerElement.isTypePermitted(obj.type)) return;
|
|
var el = OutlinerElement.fromSave(obj).addTo(target).selectLow();
|
|
el.createUniqueName();
|
|
elements.push(el);
|
|
})
|
|
Canvas.updateView({elements});
|
|
}
|
|
|
|
//Rotate Cubes
|
|
if (!Format.rotate_cubes) {
|
|
elements.forEach(cube => {
|
|
if (cube instanceof Cube == false) return;
|
|
cube.rotation.V3_set(0, 0, 0)
|
|
})
|
|
Canvas.updateView({elements, element_aspects: {transform: true}});
|
|
}
|
|
|
|
//Canvas Limit
|
|
if (Format.canvas_limit && !settings.deactivate_size_limit.value) {
|
|
|
|
elements.forEach(s => {
|
|
if (s instanceof Cube == false) return;
|
|
//Push elements into 3x3 block box
|
|
[0, 1, 2].forEach(function(ax) {
|
|
var overlap = s.to[ax] + s.inflate - 32
|
|
if (overlap > 0) {
|
|
//If positive site overlaps
|
|
s.from[ax] -= overlap
|
|
s.to[ax] -= overlap
|
|
|
|
if (16 + s.from[ax] - s.inflate < 0) {
|
|
s.from[ax] = -16 + s.inflate
|
|
}
|
|
} else {
|
|
overlap = s.from[ax] - s.inflate + 16
|
|
if (overlap < 0) {
|
|
s.from[ax] -= overlap
|
|
s.to[ax] -= overlap
|
|
|
|
if (s.to[ax] + s.inflate > 32) {
|
|
s.to[ax] = 32 - s.inflate
|
|
}
|
|
}
|
|
}
|
|
})
|
|
})
|
|
Canvas.updateView({elements, element_aspects: {transform: true, geometry: true}});
|
|
}
|
|
|
|
//Rotation Limit
|
|
if (Format.rotation_limit && Format.rotate_cubes) {
|
|
elements.forEach(cube => {
|
|
if (cube instanceof Cube == false) return;
|
|
if (!cube.rotation.allEqual(0)) {
|
|
var axis = (cube.rotation_axis && getAxisNumber(cube.rotation_axis)) || 0;
|
|
var angle = limitNumber( Math.round(cube.rotation[axis]/22.5)*22.5, -45, 45 );
|
|
cube.rotation.V3_set(0, 0, 0);
|
|
cube.rotation[axis] = angle;
|
|
}
|
|
})
|
|
Canvas.updateView({elements, element_aspects: {transform: true}});
|
|
}
|
|
|
|
Undo.finishEdit('Paste Elements', {outliner: true, elements: selected, selection: true});
|
|
}
|
|
}
|
|
|
|
BARS.defineActions(function() {
|
|
|
|
new Action('copy', {
|
|
icon: 'fa-copy',
|
|
category: 'edit',
|
|
work_in_dialog: true,
|
|
condition: () => Clipbench.getCopyType(1, true),
|
|
keybind: new Keybind({key: 'c', ctrl: true, shift: null}),
|
|
click: function (event) {Clipbench.copy(event)}
|
|
})
|
|
new Action('cut', {
|
|
icon: 'fa-cut',
|
|
category: 'edit',
|
|
work_in_dialog: true,
|
|
condition: () => Clipbench.getCopyType(1, true),
|
|
keybind: new Keybind({key: 'x', ctrl: true, shift: null}),
|
|
click: function (event) {Clipbench.copy(event, true)}
|
|
})
|
|
new Action('paste', {
|
|
icon: 'fa-clipboard',
|
|
category: 'edit',
|
|
work_in_dialog: true,
|
|
condition: () => Clipbench.getCopyType(2, true),
|
|
keybind: new Keybind({key: 'v', ctrl: true, shift: null}),
|
|
click: function (event) {Clipbench.paste(event)}
|
|
})
|
|
}) |