Add recent projects and tabs into Action Control

This commit is contained in:
JannisX11 2021-08-27 22:43:01 +02:00
parent 223aaad47a
commit 796f2904d9
6 changed files with 172 additions and 86 deletions

View File

@ -1126,7 +1126,8 @@
color: var(--color-text);
height: auto;
padding: 5px;
font-size: 0.94em
font-size: 0.94em;
word-break: break-word;
}
#action_selector ul > li {
height: 30px;

View File

@ -429,11 +429,18 @@
flex-direction: row;
position: relative;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
padding-left: 4px;
background: var(--color-frame);
}
#tab_bar #tab_bar_list {
display: flex;
flex-direction: row;
position: relative;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
margin-right: auto;
}
#tab_bar .project_tab {
background-color: var(--color-back);
cursor: pointer;
@ -515,10 +522,22 @@
text-align: center;
cursor: pointer;
padding-top: 4px;
flex-shrink: 0;
}
#new_tab_button:hover {
color: var(--color-light);
}
#search_tab_button {
height: 100%;
width: 32px;
text-align: center;
cursor: pointer;
padding-top: 4px;
flex-shrink: 0;
}
#search_tab_button:hover {
color: var(--color-light);
}
#tab_bar .project_tab > label.project_tab_session_badge {
display: flex;
flex-grow: 0;

View File

@ -358,31 +358,36 @@
<div id="blackout"></div>
<div id="tab_bar" :class="{drag_mode: drag_target_index !== null}">
<div
class="project_tab"
v-for="(project, index) in tabs" :key="project.uuid"
:class="{
selected: project.selected,
new_tab: project.is_new_tab,
dragging: index == drag_target_index,
move_back: (drag_position_index !== null && index > drag_target_index && drag_position_index >= index),
move_forth: (drag_position_index !== null && index < drag_target_index && drag_position_index <= index)
}"
:title="project.name || project.geometry_name"
@dblclick="project.openSettings()"
@mousedown="mouseDown(project, $event)"
@mouseup="mouseUp(project, $event)"
@mouseenter="mouseEnter(project, $event)"
@mouseleave="mouseLeave(project, $event)"
>
<label class="project_tab_session_badge" v-if="project.EditSession"><i class="material-icons">group</i>{{ project.EditSession.client_count }}</label>
<label>{{ project.name || project.geometry_name || project.format.name }}</label>
<div class="project_tab_close_button" :class="{unsaved: !project.saved}" :title="close_tab_label" @click="project.close()">
<i class="material-icons">{{ project.saved ? 'clear' : 'fiber_manual_record' }}</i>
<div id="tab_bar_list">
<div
class="project_tab"
v-for="(project, index) in tabs" :key="project.uuid"
:class="{
selected: project.selected,
new_tab: project.is_new_tab,
dragging: index == drag_target_index,
move_back: (drag_position_index !== null && index > drag_target_index && drag_position_index >= index),
move_forth: (drag_position_index !== null && index < drag_target_index && drag_position_index <= index)
}"
:title="project.name || project.geometry_name"
@dblclick="project.openSettings()"
@mousedown="mouseDown(project, $event)"
@mouseup="mouseUp(project, $event)"
@mouseenter="mouseEnter(project, $event)"
@mouseleave="mouseLeave(project, $event)"
>
<label class="project_tab_session_badge" v-if="project.EditSession"><i class="material-icons">group</i>{{ project.EditSession.client_count }}</label>
<label>{{ project.name || project.geometry_name || project.format.name }}</label>
<div class="project_tab_close_button" :class="{unsaved: !project.saved}" :title="close_tab_label" @click="project.close()">
<i class="material-icons">{{ project.saved ? 'clear' : 'fiber_manual_record' }}</i>
</div>
</div>
<div id="new_tab_button" v-if="!new_tab.visible" @click="openNewTab()" :title="new_tab.name">
<i class="material-icons">add</i>
</div>
</div>
<div id="new_tab_button" v-if="!new_tab.visible" @click="openNewTab()" :title="new_tab.name">
<i class="material-icons">add</i>
<div id="search_tab_button" @click="searchTabs()" :title="search_tabs_label">
<i class="material-icons">search</i>
</div>
</div>

View File

@ -2226,33 +2226,82 @@ const BARS = {
length: 0,
list: []
},
computed: {
actions() {
methods: {
updateSearch() {
var search_input = this._data.search_input.toUpperCase()
var list = this._data.list.empty()
for (var i = 0; i < Keybinds.actions.length; i++) {
var item = Keybinds.actions[i];
if (
search_input.length == 0 ||
item.name.toUpperCase().includes(search_input) ||
item.id.toUpperCase().includes(search_input)
) {
if (item instanceof Action && Condition(item.condition)) {
list.push(item)
if (list.length > ActionControl.max_length) break;
var type;
if (search_input.includes(':')) {
[type, search_input] = search_input.split(/:\s*(.*)/);
search_input = search_input || '';
}
var list = this._data.list.empty();
if (!type) {
for (var i = 0; i < Keybinds.actions.length; i++) {
var item = Keybinds.actions[i];
if (
search_input.length == 0 ||
item.name.toUpperCase().includes(search_input) ||
item.id.toUpperCase().includes(search_input)
) {
if (item instanceof Action && Condition(item.condition)) {
list.push(item)
if (list.length > ActionControl.max_length) break;
}
}
}
}
if (list.length <= ActionControl.max_length) {
for (let key in settings) {
let setting = settings[key];
if (
search_input.length == 0 ||
setting.name.toUpperCase().includes(search_input) ||
key.toUpperCase().includes(search_input)
) {
if (Condition(setting.condition)) {
list.push(setting)
if (!type || type == 'SETTINGS') {
if (list.length <= ActionControl.max_length) {
for (let key in settings) {
let setting = settings[key];
if (
search_input.length == 0 ||
setting.name.toUpperCase().includes(search_input) ||
key.toUpperCase().includes(search_input)
) {
if (Condition(setting.condition)) {
list.push(setting)
if (list.length > ActionControl.max_length) break;
}
}
}
}
}
if (isApp && type == 'RECENT') {
if (list.length <= ActionControl.max_length) {
for (let project of recent_projects) {
if (
search_input.length == 0 ||
project.path.toUpperCase().includes(search_input)
) {
list.push({
name: project.name,
icon: project.icon,
description: project.path,
keybind_label: StartScreen.vue.getDate(project),
type: 'recent_project'
})
if (list.length > ActionControl.max_length) break;
}
}
}
}
if (isApp && type == 'TAB') {
if (list.length <= ActionControl.max_length) {
for (let project of ModelProject.all) {
if (
search_input.length == 0 ||
project.name.toUpperCase().includes(search_input) ||
project.geometry_name.toUpperCase().includes(search_input)
) {
list.push({
name: project.name,
icon: project.format.icon,
description: project.path,
keybind_label: Modes.options[project.mode].name,
uuid: project.uuid,
type: 'project_tab'
})
if (list.length > ActionControl.max_length) break;
}
}
@ -2266,11 +2315,9 @@ const BARS = {
this._data.index = list.length-1;
}
return list;
}
},
methods: {
},
subtext() {
let action = this.actions[this.index];
let action = this.list[this.index];
if (Pressing.alt) {
if (action instanceof Setting) {
if (action.type == 'select') {
@ -2286,20 +2333,29 @@ const BARS = {
}
}
},
watch: {
search_input() {
this.updateSearch();
}
},
template: `
<dialog id="action_selector" v-if="open">
<input type="text" v-model="search_input" @input="e => search_input = e.target.value" autocomplete="off" autosave="off" autocorrect="off" spellcheck="off" autocapitalize="off">
<i class="material-icons" id="action_search_bar_icon">search</i>
<div id="action_selector_list">
<ul>
<li v-for="(item, i) in actions"
v-html="item.menu_node.innerHTML"
<li v-for="(item, i) in list"
:class="{selected: i === index}"
:title="item.description"
@click="ActionControl.click(item, $event)"
@mouseenter="index = i"
></li>
>
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
<span>{{ item.name }}</span>
<label class="keybinding_label">{{ item.keybind_label || (item.keybind ? item.keybind.label : '') }}</label>
</li>
</ul>
<div class="small_text" v-if="actions[index]">{{ subtext() }}</div>
<div class="small_text" v-if="list[index]">{{ subtext() }}</div>
</div>
</dialog>
`
@ -2325,19 +2381,24 @@ const ActionControl = {
set open(state) {ActionControl.vue._data.open = !!state},
type: 'action_selector',
max_length: 32,
select() {
select(input) {
ActionControl.open = true;
open_interface = ActionControl;
ActionControl.vue._data.index = 0;
ActionControl.vue.updateSearch();
if (input) {
ActionControl.vue.search_input = input;
}
Vue.nextTick(_ => {
$('#action_selector > input').focus().select();
let element = $('#action_selector > input');
element.trigger('focus');
if (!input) element.trigger('select');
})
// Update settings icons. Might need to be moved
for (let key in settings) {
let setting = settings[key];
if (setting.type == 'toggle') {
setting.menu_node.children[0].innerText = setting.value ? 'check_box' : 'check_box_outline_blank';
setting.icon = setting.value ? 'check_box' : 'check_box_outline_blank';
}
}
},
@ -2361,7 +2422,15 @@ const ActionControl = {
$('body').effect('shake');
Blockbench.showQuickMessage('Congratulations! You have discovered recursion!', 3000)
}
action.trigger(e);
if (action.type == 'recent_project') {
Blockbench.read([action.description], {}, files => {
loadModelFile(files[0]);
})
} else if (action.type == 'project_tab') {
ModelProject.all.find(p => p.uuid == action.uuid).select();
} else {
action.trigger(e);
}
},
click(action, e) {
ActionControl.trigger(action, e)

View File

@ -58,29 +58,15 @@ class Setting {
})
}
// Menu node for action control
this.menu_node = document.createElement('li');
var icon = this.icon;
if (!icon) {
if (this.type == 'toggle') icon = this.value ? 'check_box' : 'check_box_outline_blank';
if (this.type == 'number') icon = 'tag';
if (this.type == 'password') icon = 'password';
if (this.type == 'text') icon = 'format_color_text';
if (this.type == 'select') icon = 'list';
if (!icon) icon = 'settings';
if (!this.icon) {
if (this.type == 'toggle') this.icon = this.value ? 'check_box' : 'check_box_outline_blank';
if (this.type == 'number') this.icon = 'tag';
if (this.type == 'password') this.icon = 'password';
if (this.type == 'text') this.icon = 'format_color_text';
if (this.type == 'select') this.icon = 'list';
if (!this.icon) this.icon = 'settings';
}
let icon_node = Blockbench.getIconNode(icon);
this.menu_node.append(icon_node);
let span = document.createElement('span');
span.innerText = this.name;
this.menu_node.append(span);
let label = document.createElement('label');
label.innerText = tl('data.setting');
label.className = 'keybinding_label';
this.menu_node.append(label);
this.keybind_label = tl('data.setting');
}
delete() {
if (settings[this.id]) {

View File

@ -415,6 +415,7 @@ onVueSetup(() => {
drag_target_index: null,
drag_position_index: null,
close_tab_label: tl('projects.close_tab'),
search_tabs_label: tl('generic.search'),
new_tab: {
name: tl('projects.new_tab'),
saved: true,
@ -451,13 +452,18 @@ onVueSetup(() => {
this.new_tab.select();
setStartScreen(true);
},
searchTabs() {
ActionControl.select('tab:');
},
mouseDown(tab, e1) {
convertTouchEvent(e1);
e1.preventDefault();
if (this.thumbnail) {
this.thumbnail.remove();
delete this.thumbnail;
}
if (e1.button == 1) return;
let scope = this;
let active = false;
@ -564,10 +570,10 @@ onVueSetup(() => {
mouseLeave() {
if (this.thumbnail) {
this.thumbnail_timeout = setTimeout(() => {
this.thumbnail.remove();
if (this.thumbnail) this.thumbnail.remove();
delete this.thumbnail;
delete this.thumbnail_timeout;
}, 40)
}, 80)
}
}
}