Keybinding dialog now displays category conflicts again

Support format "features" inside conditions
Fix issue with clicking actions in action control
Add mesh UV rotate actions
UV size sliders now work for meshes
Complete blender keymap
This commit is contained in:
JannisX11 2021-10-02 17:06:29 +02:00
parent e0b0f1cf2c
commit f7f1b53455
12 changed files with 160 additions and 39 deletions

View File

@ -315,7 +315,17 @@
background-color: var(--color-ui);
border-left: 4px solid var(--color-accent);
}
.dialog_sidebar .dialog_sidebar_pages li.error::after {
content: "";
position: absolute;
display: block;
background-color: var(--color-close);
border-radius: 10px;
width: 10px;
height: 10px;
right: 6px;
margin-top: -17px;
}
.dialog_sidebar .dialog_sidebar_actions {
bottom: 10px;

View File

@ -2427,6 +2427,7 @@ const BARS = {
return action.description;
}
},
click: ActionControl.click,
getIconNode: Blockbench.getIconNode
},
watch: {
@ -2444,7 +2445,7 @@ const BARS = {
<li v-for="(item, i) in list"
:class="{selected: i === index}"
:title="item.description"
@click="ActionControl.click(item, $event)"
@click="click(item, $event)"
@mouseenter="index = i"
>
<div class="icon_wrapper normal" v-html="getIconNode(item.icon, item.color).outerHTML"></div>

View File

@ -330,6 +330,7 @@ class DialogSidebar {
for (let key in this.pages) {
let li = document.createElement('li');
li.textContent = this.pages[key];
li.setAttribute('page', key);
if (this.page == key) li.classList.add('selected');
this.page_menu[key] = li;
li.addEventListener('click', event => {

View File

@ -304,6 +304,7 @@ Keybinds.no_overlap = function(k1, k2) {
if (k1.condition.modes && k2.condition.modes && k1.condition.modes.overlap(k2.condition.modes) == 0) return true;
if (k1.condition.tools && k2.condition.tools && k1.condition.tools.overlap(k2.condition.tools) == 0) return true;
if (k1.condition.formats && k2.condition.formats && k1.condition.formats.overlap(k2.condition.formats) == 0) return true;
if (k1.condition.features && k2.condition.features && k1.condition.features.overlap(k2.condition.features) == 0) return true;
return false;
}
function updateKeybindConflicts() {
@ -333,6 +334,13 @@ function updateKeybindConflicts() {
}
}
})
if (Keybinds.dialog && Keybinds.dialog.sidebar.node) {
let node = Keybinds.dialog.sidebar.node;
for (var key in Keybinds.structure) {
let page = node.querySelector(`.dialog_sidebar_pages li[page="${key}"]`)
page.classList.toggle('error', Keybinds.structure[key].conflict);
}
}
}
@ -530,12 +538,10 @@ onVueSetup(function() {
<li v-for="action in list">
<div v-bind:title="action.description">{{action.name}}</div>
<div class="keybindslot" :class="{conflict: action.keybind && action.keybind.conflict}" @click.stop="record(action)" v-html="action.keybind ? action.keybind.getText(true) : ''"></div>
<div class="tool" v-on:click="reset(action)">
<div class="tooltip">${tl('keybindings.reset')}</div>
<div class="tool" v-on:click="reset(action)" title="${tl('keybindings.reset')}">
<i class="material-icons">replay</i>
</div>
<div class="tool" v-on:click="clear(action)">
<div class="tooltip">${tl('keybindings.clear')}</div>
<div class="tool" v-on:click="clear(action)" title="${tl('keybindings.clear')}">
<i class="material-icons">clear</i>
</div>
</li>

View File

@ -48,6 +48,14 @@ class MeshFace extends Face {
return direction
}
}
getBoundingRect() {
let min_x = Project.texture_width, min_y = Project.texture_height, max_x = 0, max_y = 0;
this.vertices.forEach(vkey => {
min_x = Math.min(min_x, this.uv[vkey][0]); max_x = Math.max(max_x, this.uv[vkey][0]);
min_y = Math.min(min_y, this.uv[vkey][1]); max_y = Math.max(max_y, this.uv[vkey][1]);
})
return getRectangle(min_x, min_y, max_x, max_y);
}
invert() {
if (this.vertices.length < 3) return this;
[this.vertices[0], this.vertices[1]] = [this.vertices[1], this.vertices[0]];
@ -1194,7 +1202,7 @@ BARS.defineActions(function() {
new Action('add_mesh', {
icon: 'fa-gem',
category: 'edit',
condition: () => (Modes.edit && Format.meshes),
condition: {modes: ['edit'], method: () => (Format.meshes)},
click: function () {
add_mesh_dialog.show();
}
@ -1231,7 +1239,7 @@ BARS.defineActions(function() {
icon: 'fas.fa-draw-polygon',
category: 'edit',
keybind: new Keybind({key: 'f', shift: true}),
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1)},
click() {
let vec1 = new THREE.Vector3(),
vec2 = new THREE.Vector3(),
@ -1350,7 +1358,7 @@ BARS.defineActions(function() {
new Action('convert_to_mesh', {
icon: 'fa-gem',
category: 'edit',
condition: () => (Modes.edit && Format.meshes && Cube.selected.length),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Cube.selected.length)},
click() {
Undo.initEdit({elements: Cube.selected});
@ -1407,8 +1415,7 @@ BARS.defineActions(function() {
new Action('invert_face', {
icon: 'flip_to_back',
category: 'edit',
keybind: new Keybind({key: 'i', shift: true, ctrl: true}),
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedFaces().length),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedFaces().length)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1427,7 +1434,7 @@ BARS.defineActions(function() {
icon: 'upload',
category: 'edit',
keybind: new Keybind({key: 'e', shift: true}),
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1551,7 +1558,7 @@ BARS.defineActions(function() {
icon: 'fa-compress-arrows-alt',
category: 'edit',
keybind: new Keybind({key: 'i', shift: true}),
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length >= 3),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length >= 3)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1657,7 +1664,7 @@ BARS.defineActions(function() {
icon: 'carpenter',
category: 'edit',
keybind: new Keybind({key: 'r', shift: true}),
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1800,7 +1807,7 @@ BARS.defineActions(function() {
new Action('dissolve_edges', {
icon: 'border_vertical',
category: 'edit',
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1852,7 +1859,7 @@ BARS.defineActions(function() {
icon: 'close_fullscreen',
category: 'edit',
keybind: new Keybind({key: 'm', shift: true}),
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1891,7 +1898,7 @@ BARS.defineActions(function() {
new Action('merge_vertices_by_distance', {
icon: 'close_fullscreen',
category: 'edit',
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length > 1)},
click() {
Undo.initEdit({elements: Mesh.selected});
Mesh.selected.forEach(mesh => {
@ -1953,7 +1960,7 @@ BARS.defineActions(function() {
new Action('merge_meshes', {
icon: 'upload',
category: 'edit',
condition: () => (Modes.edit && Format.meshes && Mesh.selected.length >= 2),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected.length >= 2)},
click() {
let elements = Mesh.selected
Undo.initEdit({elements});
@ -1997,7 +2004,7 @@ BARS.defineActions(function() {
new Action('split_mesh', {
icon: 'call_split',
category: 'edit',
condition: () => (Modes.edit && Format.meshes && Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length),
condition: {modes: ['edit'], features: ['meshes'], method: () => (Mesh.selected[0] && Mesh.selected[0].getSelectedVertices().length)},
click() {
let elements = Mesh.selected.slice();
Undo.initEdit({elements});
@ -2054,7 +2061,7 @@ BARS.defineActions(function() {
new Action('import_obj', {
icon: 'fa-gem',
category: 'file',
condition: () => (Modes.edit && Format.meshes),
condition: {modes: ['edit'], method: () => (Format.meshes)},
click: function () {

View File

@ -315,7 +315,6 @@ BARS.defineActions(function() {
id: 'add_texture_mesh',
icon: 'fa-puzzle-piece',
category: 'edit',
keybind: new Keybind({key: 'n', ctrl: true}),
condition: () => (Modes.edit && Format.texture_meshes),
click: function () {

View File

@ -605,7 +605,6 @@ BARS.defineActions(function() {
new Action('reload_plugins', {
icon: 'sync',
category: 'blockbench',
keybind: new Keybind({ctrl: true, key: 74}),
click: function () {
Plugins.devReload()
}

View File

@ -594,6 +594,21 @@ const UVEditor = {
Canvas.updateUV(obj)
}
})
Mesh.selected.forEach(mesh => {
mesh.forAllFaces((face, fkey) => {
if (!this.selected_faces.includes(fkey)) return;
let rect = face.getBoundingRect();
let start = (axis ? rect.ay : rect.ax);
let size = (axis ? rect.y : rect.x);
let multiplier = modify(size) / size;
face.vertices.forEach(vkey => {
if (!face.uv[vkey]) return;
face.uv[vkey][axis] = (face.uv[vkey][axis] - start) * multiplier + start;
if (isNaN(face.uv[vkey][axis])) face.uv[vkey][axis] = start;
console.log(face.uv[vkey][axis]);
})
})
})
this.displaySliders()
this.disableAutoUV()
this.vue.$forceUpdate()
@ -1001,14 +1016,40 @@ const UVEditor = {
})
this.displayTools()
},
rotate() {
rotate(mesh_angle) {
var scope = this;
var value = parseInt(BarItems.uv_rotation.get())
this.forCubes(obj => {
obj.faces[scope.face].rotation = value
Canvas.updateUV(obj)
})
this.displayTransformInfo()
Mesh.selected.forEach(mesh => {
mesh.forAllFaces((face, fkey) => {
if (!UVEditor.selected_faces.includes(fkey)) return;
if (face.vertices.length < 3) return;
let center = [0, 0];
face.vertices.forEach(vkey => {
if (!face.uv[vkey]) return;
center[0] += face.uv[vkey][0];
center[1] += face.uv[vkey][1];
})
center[0] /= face.vertices.length;
center[1] /= face.vertices.length;
face.vertices.forEach(vkey => {
if (!face.uv[vkey]) return;
let sin = Math.sin(Math.degToRad(mesh_angle));
let cos = Math.cos(Math.degToRad(mesh_angle));
face.uv[vkey][0] -= center[0];
face.uv[vkey][1] -= center[1];
let a = (face.uv[vkey][0] * cos - face.uv[vkey][1] * sin);
let b = (face.uv[vkey][0] * sin + face.uv[vkey][1] * cos);
face.uv[vkey][0] = Math.clamp(a + center[0], 0, Project.texture_width);
face.uv[vkey][1] = Math.clamp(b + center[1], 0, Project.texture_height);
})
})
})
this.loadData();
this.message('uv_editor.rotated')
},
setRotation(value) {
@ -1188,7 +1229,7 @@ const UVEditor = {
'_',
'copy',
'paste',
{icon: 'photo_size_select_large', name: 'menu.uv.mapping', condition: () => !Project.box_uv, children: function(editor) {
{icon: 'photo_size_select_large', name: 'menu.uv.mapping', condition: () => !Project.box_uv && UVEditor.getReferenceFace(), children: function(editor) {
let reference_face = UVEditor.getReferenceFace();
function isMirrored(axis) {
if (reference_face instanceof CubeFace) {
@ -1213,7 +1254,9 @@ const UVEditor = {
'uv_auto',
'uv_rel_auto',
'snap_uv_to_pixels',
{icon: 'rotate_90_degrees_ccw', condition: () => Format.uv_rotation, name: 'menu.uv.mapping.rotation', children: function() {
'uv_rotate_left',
'uv_rotate_right',
{icon: 'rotate_90_degrees_ccw', condition: () => reference_face instanceof CubeFace && Format.uv_rotation, name: 'menu.uv.mapping.rotation', children: function() {
var off = 'radio_button_unchecked'
var on = 'radio_button_checked'
return [
@ -1261,7 +1304,7 @@ const UVEditor = {
]
}},
'face_tint',
{icon: 'flip_to_back', condition: () => (Format.id == 'java_block'&& Cube.selected.length), name: 'action.cullface' , children: function() {
{icon: 'flip_to_back', condition: () => (Format.id == 'java_block' && Cube.selected.length), name: 'action.cullface' , children: function() {
var off = 'radio_button_unchecked';
var on = 'radio_button_checked';
function setCullface(cullface) {
@ -1409,6 +1452,26 @@ BARS.defineActions(function() {
Undo.finishEdit('Mirror UV')
}
})
new Action('uv_rotate_left', {
icon: 'rotate_left',
category: 'uv',
condition: () => Mesh.selected.length,
click: function (event) {
Undo.initEdit({elements: Mesh.selected, uv_only: true})
UVEditor.rotate(-90);
Undo.finishEdit('Rotate UV left');
}
})
new Action('uv_rotate_right', {
icon: 'rotate_right',
category: 'uv',
condition: () => Mesh.selected.length,
click: function (event) {
Undo.initEdit({elements: Mesh.selected, uv_only: true})
UVEditor.rotate(90);
Undo.finishEdit('Rotate UV right');
}
})
new Action('uv_transparent', {
icon: 'clear',
category: 'uv',
@ -2553,12 +2616,15 @@ Interface.definePanels(function() {
UVEditor.sliders.size_x = new NumSlider({
id: 'uv_slider_size_x',
private: true,
condition: () => (!Project.box_uv && Cube.selected[0] && UVEditor.vue.selected_faces.length),
condition: () => (!Project.box_uv && UVEditor.vue.selected_faces.length),
get: function() {
if (!Project.box_uv) {
let ref_face = UVEditor.getReferenceFace();
if (ref_face instanceof CubeFace) {
return trimFloatNumber(ref_face.uv[2] - ref_face.uv[0]);
} else if (ref_face instanceof MeshFace) {
let rect = ref_face.getBoundingRect();
return trimFloatNumber(rect.x);
}
}
return 0
@ -2574,12 +2640,15 @@ Interface.definePanels(function() {
UVEditor.sliders.size_y = new NumSlider({
id: 'uv_slider_size_y',
private: true,
condition: () => (!Project.box_uv && Cube.selected[0] && UVEditor.vue.selected_faces.length),
condition: () => (!Project.box_uv && UVEditor.vue.selected_faces.length),
get: function() {
if (!Project.box_uv) {
let ref_face = UVEditor.getReferenceFace();
if (ref_face instanceof CubeFace) {
return trimFloatNumber(ref_face.uv[3] - ref_face.uv[1]);
} else if (ref_face instanceof MeshFace) {
let rect = ref_face.getBoundingRect();
return trimFloatNumber(rect.y);
}
}
return 0

View File

@ -39,6 +39,7 @@ const Condition = function(condition, context) {
if (condition.modes instanceof Array && condition.modes.includes(Modes.id) === false) return false;
if (condition.formats instanceof Array && condition.formats.includes(Format.id) === false) return false;
if (condition.tools instanceof Array && window.Toolbox && condition.tools.includes(Toolbox.selected.id) === false) return false;
if (condition.features instanceof Array && Format && condition.features.find(feature => !Format[feature])) return false;
if (condition.method instanceof Function) {
return condition.method(context);

File diff suppressed because one or more lines are too long

View File

@ -16,31 +16,32 @@
"swap_tools": {"key": 32},
"open_model_folder": null,
"open_backup_folder": null,
"settings_window": null,
"keybindings_window": null,
"theme_window": null,
"reload": {"key": 116},
"rename": {"key": 113},
"delete": {"key": 46},
"duplicate": {"key": 68, "shift": true},
"find_replace": null,
"open_dev_tools": {"key": 73, "ctrl": true, "shift": true},
"fullscreen": {"key": 122},
"zoom_in": null,
"zoom_out": null,
"zoom_reset": null,
"toggle_sidebars": {"key": 66, "ctrl": true},
"action_control": {"key": 70},
"action_control": {"key": 114},
"theme_window": null,
"import_theme": null,
"export_theme": null,
"reset_layout": null,
"start": null,
"about_window": null,
"edit": {"key": 49},
"paint": {"key": 50},
"display": {"key": 51},
"animate": {"key": 52},
"keybindings_window": null,
"load_keymap": null,
"import_keymap": null,
"export_keymap": null,
"settings_window": null,
"import_settings": null,
"export_settings": null,
"copy": {"key": 67, "ctrl": true},
@ -58,13 +59,29 @@
"select_window": {"key": 70, "ctrl": true},
"invert_selection": {"key": 73, "ctrl": true},
"select_all": {"key": 65},
"hide_everything_except_selection": {"key": 72, "ctrl": true},
"add_group": {"key": 71, "ctrl": true},
"group_elements": {"key": 71, "ctrl": true, "shift": true},
"collapse_groups": null,
"unfold_groups": null,
"edit_bedrock_binding": null,
"add_mesh": null,
"selection_mode": null,
"create_face": {"key": 70},
"convert_to_mesh": null,
"invert_face": null,
"extrude_mesh_selection": {"key": 69},
"inset_mesh_selection": {"key": 73},
"loop_cut": {"key": 82, "ctrl": true},
"dissolve_edges": {"key": 88, "ctrl": true},
"merge_vertices": {"key": 77, "shift": true},
"merge_vertices_by_distance": null,
"merge_meshes": {"key": 77},
"split_mesh": null,
"import_obj": null,
"add_cube": {"key": 78, "ctrl": true},
"edit_material_instances": null,
"add_texture_mesh": null,
"add_locator": null,
"add_null_object": null,
"view_mode": {"key": 90, "shift": true},
@ -140,7 +157,6 @@
"animated_texture_frame": null,
"uv_rotation": null,
"uv_grid": null,
"uv_select_all": null,
"uv_maximize": null,
"uv_turn_mapping": null,
"uv_auto": null,
@ -154,17 +170,19 @@
"auto_cullface": null,
"face_tint": null,
"slider_face_tint": null,
"snap_uv_to_pixels": null,
"toggle_uv_overlay": null,
"brush_tool": {"key": 66},
"fill_tool": null,
"eraser": {"key": 69, "ctrl": true},
"color_picker": {"key": 69},
"color_picker": null,
"draw_shape_tool": {"key": 85},
"gradient_tool": null,
"copy_paste_tool": {"key": 77},
"draw_shape_type": null,
"fill_mode": null,
"mirror_painting": null,
"color_erase_mode": null,
"lock_alpha": null,
"painting_grid": {"key": 71, "shift": true},
"slider_brush_size": null,
@ -198,13 +216,14 @@
"previous_keyframe": null,
"next_keyframe": null,
"slider_keyframe_time": null,
"keyframe_uniform": null,
"keyframe_interpolation": {"key": 84},
"reset_keyframe": null,
"resolve_keyframe_expressions": null,
"change_keyframe_file": null,
"reverse_keyframes": null,
"flip_animation": null,
"timeline_graph_editor": {"key": 114},
"timeline_graph_editor": {"key": 114, "ctrl": true},
"graph_editor_zero_line": null,
"play_animation": {"key": 32},
"slider_animation_speed": null,
@ -219,13 +238,16 @@
"timeline_focus": null,
"add_marker": {"key": 77},
"plugins_window": null,
"reload_plugins": {"key": 74, "ctrl": true},
"reload_plugins": null,
"load_plugin": null,
"load_plugin_from_url": null,
"add_plugin": null,
"remove_plugin": null,
"project_window": null,
"close_project": null,
"convert_project": null,
"open_model": {"key": 79, "ctrl": true},
"open_from_link": null,
"extrude_texture": null,
"export_over": {"key": 83, "ctrl": true},
"upload_sketchfab": null,

View File

@ -1152,6 +1152,10 @@
"action.uv_mirror_x.desc": "Mirrors the UV of this face on the X axis",
"action.uv_mirror_y": "UV Mirror Y",
"action.uv_mirror_y.desc": "Mirrors the UV of this face on the Y axis",
"action.uv_rotate_left": "Rotate UV Left",
"action.uv_rotate_left.desc": "Rotate the selected UV faces counter-clockwise",
"action.uv_rotate_right": "Rotate UV Right",
"action.uv_rotate_right.desc": "Rotate the selected UV faces clockwise",
"action.uv_transparent": "Remove Face",
"action.uv_transparent.desc": "Removes the current face",
"action.uv_reset": "Reset Face",
@ -1437,6 +1441,8 @@
"panel.bone.ik": "Inverse Kinematics (Experimental)",
"uv_editor.title": "UV Editor",
"uv_editor.show_all_faces": "Show All Faces",
"uv_editor.show_selected_faces": "Show Selected Faces",
"uv_editor.all_faces": "All",
"uv_editor.no_faces": "None",
"uv_editor.rotated": "Rotated",