mirror of
https://github.com/JannisX11/blockbench.git
synced 2024-11-27 04:21:46 +08:00
parent
6b1de30bf8
commit
ebea154699
@ -592,6 +592,27 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
.contextMenu .menu_search_bar {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
border: 1px solid var(--color-border);
|
||||
margin: 2px;
|
||||
}
|
||||
.contextMenu .menu_search_bar input {
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
flex-grow: 1;
|
||||
height: auto;
|
||||
}
|
||||
.contextMenu .menu_search_bar div {
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.contextMenu .menu_search_bar div > * {
|
||||
pointer-events: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.keybinding_label {
|
||||
pointer-events: none;
|
||||
|
@ -210,6 +210,7 @@ class Action extends BarItem {
|
||||
}
|
||||
if (data.condition) this.condition = data.condition
|
||||
this.children = data.children;
|
||||
this.searchable = data.searchable;
|
||||
|
||||
//Node
|
||||
if (!this.click) this.click = data.click
|
||||
|
@ -17,12 +17,16 @@ function handleMenuOverflow(node) {
|
||||
})
|
||||
}
|
||||
class Menu {
|
||||
constructor(id, structure) {
|
||||
if (!structure) structure = id;
|
||||
constructor(id, structure, options) {
|
||||
if (typeof id !== 'string') {
|
||||
options = structure;
|
||||
structure = id;
|
||||
}
|
||||
this.id = typeof id == 'string' ? id : '';
|
||||
this.children = [];
|
||||
this.node = $('<ul class="contextMenu"></ul>')[0]
|
||||
this.structure = structure
|
||||
this.structure = structure;
|
||||
this.options = options || {};
|
||||
}
|
||||
hover(node, event, expand) {
|
||||
if (event) event.stopPropagation()
|
||||
@ -146,13 +150,9 @@ class Menu {
|
||||
node.find('ul.contextMenu.sub').detach();
|
||||
if (list.length) {
|
||||
var childlist = $('<ul class="contextMenu sub"></ul>')
|
||||
list.forEach(function(s2, i) {
|
||||
getEntry(s2, childlist)
|
||||
})
|
||||
var last = childlist.children().last()
|
||||
if (last.length && last.hasClass('menu_separator')) {
|
||||
last.remove()
|
||||
}
|
||||
|
||||
populateList(list, childlist, object.searchable);
|
||||
|
||||
if (typeof object.click == 'function' && object instanceof Action == false) {
|
||||
node.addClass('hybrid_parent');
|
||||
let more_button = Interface.createElement('div', {class: 'menu_more_button'}, Blockbench.getIconNode('more_horiz'));
|
||||
@ -168,6 +168,59 @@ class Menu {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function populateList(list, menu_node, searchable) {
|
||||
|
||||
if (searchable) {
|
||||
let input = Interface.createElement('input', {type: 'text', placeholder: tl('generic.search')});
|
||||
let search_button = Interface.createElement('div', {}, Blockbench.getIconNode('search'));
|
||||
let search_bar = Interface.createElement('li', {class: 'menu_search_bar'}, [input, search_button]);
|
||||
menu_node.append(search_bar);
|
||||
|
||||
let object_list = [];
|
||||
list.forEach(function(s2, i) {
|
||||
let jq_node = getEntry(s2, menu_node);
|
||||
if (!jq_node) return;
|
||||
object_list.push({
|
||||
object: s2,
|
||||
node: jq_node[0] || jq_node,
|
||||
id: s2.id,
|
||||
name: s2.name,
|
||||
description: s2.description,
|
||||
})
|
||||
})
|
||||
search_button.onclick = (e) => {
|
||||
input.value = '';
|
||||
}
|
||||
input.oninput = (e) => {
|
||||
let search_term = input.value.toUpperCase();
|
||||
search_button.firstElementChild.replaceWith(Blockbench.getIconNode(search_term ? 'clear' : 'search'));
|
||||
|
||||
object_list.forEach(item => {
|
||||
$(item.node).detach();
|
||||
})
|
||||
object_list.forEach(item => {
|
||||
if (
|
||||
typeof item.object == 'string' ||
|
||||
item.object.always_show ||
|
||||
(item.id && item.id.toUpperCase().includes(search_term)) ||
|
||||
(item.name && item.name.toUpperCase().includes(search_term)) ||
|
||||
(item.description && item.description.toUpperCase().includes(search_term))
|
||||
) {
|
||||
menu_node.append(item.node);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
list.forEach((object) => {
|
||||
getEntry(object, menu_node);
|
||||
})
|
||||
}
|
||||
var last = menu_node.children().last();
|
||||
if (last.length && last.hasClass('menu_separator')) {
|
||||
last.remove()
|
||||
}
|
||||
}
|
||||
|
||||
function getEntry(s, parent) {
|
||||
|
||||
@ -178,7 +231,7 @@ class Menu {
|
||||
if (last.length && !last.hasClass('menu_separator')) {
|
||||
parent.append(entry)
|
||||
}
|
||||
return;
|
||||
return entry;
|
||||
}
|
||||
if (typeof s == 'string' && BarItems[s]) {
|
||||
s = BarItems[s];
|
||||
@ -291,15 +344,10 @@ class Menu {
|
||||
obj = obj.parent().parent();
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
scope.structure.forEach(function(s, i) {
|
||||
getEntry(s, ctxmenu)
|
||||
})
|
||||
var last = ctxmenu.children().last()
|
||||
if (last.length && last.hasClass('menu_separator')) {
|
||||
last.remove()
|
||||
}
|
||||
populateList(scope.structure, ctxmenu, this.options.searchable);
|
||||
|
||||
var el_width = ctxmenu.width()
|
||||
var el_height = ctxmenu.height()
|
||||
@ -350,7 +398,9 @@ class Menu {
|
||||
$(scope.node).on('click', (ev) => {
|
||||
if (
|
||||
ev.target.className.includes('parent') ||
|
||||
(ev.target.parentNode && ev.target.parentNode.className.includes('parent'))
|
||||
(ev.target.parentNode && ev.target.parentNode.className.includes('parent')) ||
|
||||
ev.target.classList.contains('menu_search_bar') ||
|
||||
(ev.target.parentNode && ev.target.parentNode.classList.contains('menu_search_bar'))
|
||||
) {} else {
|
||||
scope.hide()
|
||||
}
|
||||
@ -530,6 +580,7 @@ const MenuBar = {
|
||||
},
|
||||
{name: 'menu.file.recent', id: 'recent', icon: 'history',
|
||||
condition() {return isApp && recent_projects.length},
|
||||
searchable: true,
|
||||
children() {
|
||||
var arr = []
|
||||
let redact = settings.streamer_mode.value;
|
||||
@ -551,6 +602,7 @@ const MenuBar = {
|
||||
arr.push('_', {
|
||||
name: 'menu.file.recent.more',
|
||||
icon: 'read_more',
|
||||
always_show: true,
|
||||
click(c, event) {
|
||||
ActionControl.select('recent: ');
|
||||
}
|
||||
@ -560,6 +612,7 @@ const MenuBar = {
|
||||
arr.push('_', {
|
||||
name: 'menu.file.recent.clear',
|
||||
icon: 'clear',
|
||||
always_show: true,
|
||||
click(c, event) {
|
||||
recent_projects.empty();
|
||||
updateRecentProjects();
|
||||
|
@ -721,7 +721,7 @@ class Cube extends OutlinerElement {
|
||||
Cube.prototype.rotatable = true;
|
||||
Cube.prototype.needsUniqueName = false;
|
||||
Cube.prototype.menu = new Menu([
|
||||
'group_elements',
|
||||
...Outliner.control_menu_group,
|
||||
'_',
|
||||
'copy',
|
||||
'paste',
|
||||
|
@ -433,9 +433,7 @@ class Group extends OutlinerNode {
|
||||
Undo.finishEdit('Change group marker color')
|
||||
}
|
||||
Group.prototype.menu = new Menu([
|
||||
'copy',
|
||||
'paste',
|
||||
'duplicate',
|
||||
...Outliner.control_menu_group,
|
||||
'_',
|
||||
'add_locator',
|
||||
'_',
|
||||
@ -566,7 +564,7 @@ BARS.defineActions(function() {
|
||||
}
|
||||
})
|
||||
new Action('group_elements', {
|
||||
icon: 'drive_file_move',
|
||||
icon: 'drive_folder_upload',
|
||||
category: 'edit',
|
||||
condition: () => Modes.edit && (selected.length || Group.selected),
|
||||
keybind: new Keybind({key: 'g', ctrl: true, shift: true}),
|
||||
|
@ -104,7 +104,7 @@ class Locator extends OutlinerElement {
|
||||
}
|
||||
},
|
||||
'_',
|
||||
'group_elements',
|
||||
...Outliner.control_menu_group,
|
||||
'_',
|
||||
'copy',
|
||||
'paste',
|
||||
|
@ -616,11 +616,7 @@ class Mesh extends OutlinerElement {
|
||||
'_',
|
||||
'split_mesh',
|
||||
'merge_meshes',
|
||||
'group_elements',
|
||||
'_',
|
||||
'copy',
|
||||
'paste',
|
||||
'duplicate',
|
||||
...Outliner.control_menu_group,
|
||||
'_',
|
||||
'rename',
|
||||
{name: 'menu.cube.color', icon: 'color_lens', children: markerColors.map((color, i) => {return {
|
||||
|
@ -126,11 +126,7 @@ class NullObject extends OutlinerElement {
|
||||
}
|
||||
},
|
||||
'_',
|
||||
'group_elements',
|
||||
'_',
|
||||
'copy',
|
||||
'paste',
|
||||
'duplicate',
|
||||
Outliner.control_menu_group,
|
||||
'_',
|
||||
'rename',
|
||||
'delete'
|
||||
|
@ -609,6 +609,13 @@ class NodePreviewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
Outliner.control_menu_group = [
|
||||
'copy',
|
||||
'paste',
|
||||
'duplicate',
|
||||
'group_elements',
|
||||
'move_to_group',
|
||||
]
|
||||
|
||||
OutlinerElement.registerType = function(constructor, id) {
|
||||
OutlinerElement.types[id] = constructor;
|
||||
@ -735,7 +742,7 @@ function parseGroups(array, import_reference, startIndex) {
|
||||
}
|
||||
|
||||
// Dropping
|
||||
function dropOutlinerObjects(item, target, event, order) {
|
||||
function moveOutlinerSelectionTo(item, target, event, order) {
|
||||
let duplicate = event.altKey || Pressing.overrides.alt;
|
||||
if (item.type === 'group' && target && target.parent) {
|
||||
var is_parent = false;
|
||||
@ -811,7 +818,7 @@ function dropOutlinerObjects(item, target, event, order) {
|
||||
updateSelection()
|
||||
Undo.finishEdit('Duplicate selection', {elements: selected, outliner: true, selection: true})
|
||||
} else {
|
||||
Undo.finishEdit('Drag elements in outliner')
|
||||
Undo.finishEdit('Move elements in outliner')
|
||||
}
|
||||
}
|
||||
|
||||
@ -957,6 +964,35 @@ BARS.defineActions(function() {
|
||||
}
|
||||
})
|
||||
|
||||
new Action('move_to_group', {
|
||||
icon: 'drive_file_move',
|
||||
category: 'edit',
|
||||
searchable: true,
|
||||
children(element) {
|
||||
let groups = getAllGroups();
|
||||
let root = {
|
||||
name: 'Root',
|
||||
icon: 'list_alt',
|
||||
click(event) {
|
||||
moveOutlinerSelectionTo(element, undefined, event);
|
||||
}
|
||||
};
|
||||
return [root, ...groups.map(group => {
|
||||
return {
|
||||
name: group.name,
|
||||
icon: 'folder',
|
||||
color: markerColors[group.color] && markerColors[group.color].standard,
|
||||
click(event) {
|
||||
moveOutlinerSelectionTo(element, group, event);
|
||||
element.showInOutliner();
|
||||
}
|
||||
}
|
||||
})]
|
||||
},
|
||||
click(event) {
|
||||
new Menu('move_to_group', this.children(this), {searchable: true}).open(event.target, this)
|
||||
}
|
||||
})
|
||||
new Action('sort_outliner', {
|
||||
icon: 'sort_by_alpha',
|
||||
category: 'edit',
|
||||
@ -1444,9 +1480,9 @@ Interface.definePanels(function() {
|
||||
let target = document.elementFromPoint(e2.clientX, e2.clientY);
|
||||
[drop_target] = eventTargetToNode(target);
|
||||
if (drop_target) {
|
||||
dropOutlinerObjects(item, drop_target, e2, order);
|
||||
moveOutlinerSelectionTo(item, drop_target, e2, order);
|
||||
} else if ($('#cubes_list').is(':hover')) {
|
||||
dropOutlinerObjects(item, undefined, e2);
|
||||
moveOutlinerSelectionTo(item, undefined, e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,7 @@ class TextureMesh extends OutlinerElement {
|
||||
TextureMesh.prototype.rotatable = true;
|
||||
TextureMesh.prototype.needsUniqueName = false;
|
||||
TextureMesh.prototype.menu = new Menu([
|
||||
'group_elements',
|
||||
'_',
|
||||
'copy',
|
||||
'paste',
|
||||
'duplicate',
|
||||
...Outliner.control_menu_group,
|
||||
'_',
|
||||
'rename',
|
||||
{name: 'menu.texture_mesh.texture_name', icon: 'collections', condition: () => !Project.single_texture, click(context) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -1001,6 +1001,8 @@
|
||||
"action.duplicate.desc": "Duplicates the selected cubes or group",
|
||||
"action.delete": "Delete",
|
||||
"action.delete.desc": "Deletes the selected cubes or group",
|
||||
"action.move_to_group": "Move to Group",
|
||||
"action.move_to_group.desc": "Move the selected elements to a different outliner group",
|
||||
"action.sort_outliner": "Sort Outliner",
|
||||
"action.sort_outliner.desc": "Sort the outliner alphabetically",
|
||||
"action.unlock_everything": "Unlock All",
|
||||
|
Loading…
Reference in New Issue
Block a user