Merge branch 'next' into poly
This commit is contained in:
commit
b193b61be3
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
242
css/dialogs.css
242
css/dialogs.css
@ -8,6 +8,21 @@
|
||||
opacity: 0.6;
|
||||
z-index: 19;
|
||||
}
|
||||
.dialog_handle {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
padding-left: 8px;
|
||||
background: var(--color-button);
|
||||
height: 30px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.dialog_handle .dialog_title {
|
||||
padding-top: 2px;
|
||||
font-size: 1.12em;
|
||||
padding-left: 16px;
|
||||
pointer-events: none;
|
||||
}
|
||||
.dialog_close_button {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
@ -21,6 +36,16 @@
|
||||
color: var(--color-light);
|
||||
background-color: var(--color-close);
|
||||
}
|
||||
.dialog_menu_button {
|
||||
height: 100%;
|
||||
width: 34px;
|
||||
padding: 4px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
}
|
||||
.dialog_menu_button:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
.dialog:not(.draggable) .dialog_close_button {
|
||||
top: 8px;
|
||||
right: -34px;
|
||||
@ -41,7 +66,7 @@
|
||||
bottom: unset;
|
||||
display: none;
|
||||
}
|
||||
dialog > content {
|
||||
dialog > content, dialog .dialog_wrapper > content {
|
||||
display: block;
|
||||
overflow-y: auto;
|
||||
flex: 1 1 auto;
|
||||
@ -72,11 +97,7 @@
|
||||
}
|
||||
.dialog:not(.ui-resizable) {
|
||||
min-width: min(400px, 100%);
|
||||
max-width: min(660px, 100%);
|
||||
}
|
||||
.dialog.paddinged {
|
||||
padding: 24px;
|
||||
padding-bottom: 12px;
|
||||
max-width: min(960px, 100%);
|
||||
}
|
||||
.dialog_bar {
|
||||
position: relative;
|
||||
@ -102,7 +123,6 @@
|
||||
}
|
||||
.dialog_bar.button_bar {
|
||||
text-align: right;
|
||||
margin-top: 12px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.dialog_bar button.large {
|
||||
@ -155,12 +175,6 @@
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
|
||||
.dialog .tab_content {
|
||||
height: calc(100% - 90px);
|
||||
width: 100%;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.dialog p {
|
||||
margin: 4px 0;
|
||||
}
|
||||
@ -238,59 +252,129 @@
|
||||
transition: color 750ms linear;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.dialog_wrapper {
|
||||
flex-grow: 1;
|
||||
display: block;
|
||||
}
|
||||
.dialog_wrapper.has_sidebar {
|
||||
display: grid;
|
||||
grid-template-rows: auto 42px;
|
||||
grid-template-columns: minmax(160px, 200px) auto;
|
||||
grid-template-areas: "sidebar content" "sidebar buttons";
|
||||
}
|
||||
.dialog_sidebar {
|
||||
background-color: var(--color-back);
|
||||
flex: 1 0 160px;
|
||||
position: relative;
|
||||
grid-area: sidebar;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.dialog_content {
|
||||
display: block;
|
||||
grid-area: content;
|
||||
max-height: calc(100vh - 180px);
|
||||
}
|
||||
dialog .dialog_content,
|
||||
dialog .dialog_bar.button_bar {
|
||||
margin: 24px;
|
||||
}
|
||||
dialog .dialog_bar.button_bar {
|
||||
grid-area: buttons;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.dialog_sidebar .dialog_sidebar_pages {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_pages li {
|
||||
width: 100%;
|
||||
padding: 4px 20px;
|
||||
border-left: 4px solid transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_pages li:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_pages li.selected {
|
||||
background-color: var(--color-ui);
|
||||
border-left: 4px solid var(--color-accent);
|
||||
}
|
||||
|
||||
|
||||
.dialog_sidebar .dialog_sidebar_actions {
|
||||
bottom: 10px;
|
||||
padding: 8px;
|
||||
margin-top: auto;
|
||||
border-top: 2px solid var(--color-border);
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_actions li {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
padding: 4px;
|
||||
padding-left: 34px;
|
||||
padding-right: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_actions li:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_actions li i {
|
||||
margin-top: 1px;
|
||||
margin-right: 4px;
|
||||
margin-left: -28px;
|
||||
flex-shrink: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_actions li img {
|
||||
cursor: default;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
color: var(--color-text);
|
||||
white-space: nowrap;
|
||||
margin-bottom: -3px;
|
||||
margin-left: -27px;
|
||||
margin-right: 5px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
.dialog_sidebar .dialog_sidebar_actions li span {
|
||||
pointer-events: none;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
|
||||
/*Settings Dialog*/
|
||||
dialog#settings {
|
||||
width: min(100%, 600px);
|
||||
dialog#settings .dialog_wrapper {
|
||||
min-height: 640px;
|
||||
}
|
||||
#settings_tab_bar {
|
||||
margin: -24px;
|
||||
margin-bottom: 0;
|
||||
margin-top: -20px;
|
||||
}
|
||||
#settings h2 {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#settings h3 > i {
|
||||
margin-top: 5px;
|
||||
float: left;
|
||||
}
|
||||
#settings h3 > i.settings_expand_icon {
|
||||
opacity: 0.7;
|
||||
}
|
||||
#settings h3:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
#settings .bar.next_to_title {
|
||||
margin-top: -60px;
|
||||
}
|
||||
dialog#settings .search_bar {
|
||||
margin-top: 26px;
|
||||
dialog#settings h2, dialog#keybindings h2, dialog#theme h2 {
|
||||
margin-top: -10px;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
|
||||
/*Settings*/
|
||||
#settings li h3 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-top: 6px;
|
||||
}
|
||||
#settingslist {
|
||||
width: 100%;
|
||||
max-height: 600px;
|
||||
overflow-y: scroll;
|
||||
clear: both;
|
||||
}
|
||||
#settingslist li > ul {
|
||||
margin-left: 24px;
|
||||
}
|
||||
#settingslist li li {
|
||||
#settingslist li {
|
||||
padding: 5px 0;
|
||||
}
|
||||
#settingslist li li:hover input[type=checkbox] {
|
||||
#settingslist li:hover input[type=checkbox] {
|
||||
color: var(--color-light);
|
||||
}
|
||||
#settingslist li > .setting_element {
|
||||
#settingslist .setting_element {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
float: left;
|
||||
@ -337,12 +421,12 @@
|
||||
#settingslist div.bar_select select {
|
||||
width: 100%;
|
||||
}
|
||||
#settingslist li li .setting_icon i {
|
||||
#settingslist li .setting_icon i {
|
||||
font-size: 26pt;
|
||||
width: 34px;
|
||||
margin-top: -6px;
|
||||
}
|
||||
#settingslist li li:hover .setting_icon i {
|
||||
#settingslist li:hover .setting_icon i {
|
||||
color: var(--color-light);
|
||||
}
|
||||
.password_toggle {
|
||||
@ -355,9 +439,12 @@
|
||||
}
|
||||
|
||||
/*Keybinds*/
|
||||
dialog#keybindings .dialog_wrapper {
|
||||
min-height: 640px;
|
||||
}
|
||||
#keybindlist {
|
||||
max-height: 600px;
|
||||
padding-bottom: 25px;
|
||||
margin-top: 16px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
clear: both;
|
||||
@ -378,6 +465,7 @@
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
cursor: text;
|
||||
}
|
||||
#keybindlist li > div.keybindslot:hover {
|
||||
color: var(--color-light);
|
||||
@ -394,17 +482,27 @@
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
#keybindlist > li > ul > li {
|
||||
#keybindlist > li {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
#keybindlist > li {
|
||||
width: 100%;
|
||||
min-height: 34px;
|
||||
padding-left: 6px;
|
||||
}
|
||||
.keybindslot .punctuation {
|
||||
color: var(--color-subtle_text);
|
||||
}
|
||||
.keybindslot .modifier, .keybindslot .key {
|
||||
background: var(--color-button);
|
||||
padding: 2px 5px;
|
||||
}
|
||||
.keybindslot .optional {
|
||||
color: var(--color-subtle_text);
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
/*Colors*/
|
||||
dialog#theme .dialog_wrapper {
|
||||
min-height: 480px;
|
||||
}
|
||||
div#color_wrapper {
|
||||
columns: 2;
|
||||
margin-bottom: 20px;
|
||||
@ -646,9 +744,10 @@
|
||||
}
|
||||
.dialog.draggable .bar.next_to_title {
|
||||
width: max-content;
|
||||
margin-top: -51px;
|
||||
margin-top: -30px;
|
||||
margin-left: 111px;
|
||||
float: left;
|
||||
z-index: inherit;
|
||||
}
|
||||
.dialog#plugins {
|
||||
width: 100%;
|
||||
@ -858,11 +957,37 @@
|
||||
}
|
||||
#bar_items_current li {
|
||||
min-width: 20px;
|
||||
cursor: move;
|
||||
}
|
||||
#bar_items_current li .toolbar_separator {
|
||||
#bar_items_current li > * {
|
||||
cursor: inherit;
|
||||
}
|
||||
#bar_items_current .toolbar_separator.border {
|
||||
height: 32px;
|
||||
width: 12px;
|
||||
background-color: var(--color-button);
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-border);
|
||||
}
|
||||
#bar_items_current .toolbar_separator.spacer {
|
||||
width: 40px;
|
||||
}
|
||||
#bar_items_current .toolbar_separator.spacer::after {
|
||||
content: "";
|
||||
border-bottom: 6px dotted var(--color-subtle_text);
|
||||
display: block;
|
||||
position: a;
|
||||
height: 18px;
|
||||
width: 32px;
|
||||
}
|
||||
#bar_items_current .toolbar_separator.linebreak {
|
||||
height: 32px;
|
||||
width: 20px;
|
||||
background-color: var(--color-dark);
|
||||
color: var(--color-subtle_text);
|
||||
}
|
||||
#bar_items_current .toolbar_separator.linebreak::after {
|
||||
content: "¶";
|
||||
font-size: 22px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/*Action Control*/
|
||||
@ -963,6 +1088,9 @@
|
||||
#bar_item_list li {
|
||||
padding: 4px;
|
||||
}
|
||||
#bar_item_list li.separator_item {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
#bar_item_list li:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
@ -188,7 +188,7 @@
|
||||
z-index: 100;
|
||||
min-width: 150px;
|
||||
max-width: 250px;
|
||||
width: min-content;
|
||||
width: fit-content;
|
||||
padding: 0 12px;
|
||||
background-color: var(--color-bright_ui);
|
||||
color: var(--color-accent_text);
|
||||
@ -360,7 +360,7 @@
|
||||
height: 10px;
|
||||
float: left;
|
||||
}
|
||||
.toolbar_separator {
|
||||
.toolbar .toolbar_separator.border {
|
||||
width: 2px;
|
||||
height: 24px;
|
||||
float: left;
|
||||
@ -368,6 +368,17 @@
|
||||
margin: 4px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.toolbar .toolbar_separator.spacer {
|
||||
background: transparent;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.toolbar .toolbar_separator.linebreak {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.text_button:hover {
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
/*Layout*/
|
||||
#page_wrapper {
|
||||
height: calc(100% - 56px);
|
||||
height: calc(100% - 26px);
|
||||
width: 100%;
|
||||
border: 2px solid var(--color-frame);
|
||||
border-top: none;
|
||||
@ -35,7 +35,7 @@
|
||||
"left_bar center right_bar"
|
||||
"left_bar status_bar right_bar";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: calc(100% - 30px);
|
||||
}
|
||||
|
||||
#tab_bar {
|
||||
|
238
index.html
238
index.html
@ -25,7 +25,7 @@
|
||||
<script>
|
||||
if (typeof module === 'object') {window.module = module; module = undefined;}//jQuery Fix
|
||||
const isApp = typeof require !== 'undefined';
|
||||
const appVersion = '3.9.2';
|
||||
const appVersion = '4.0.0-beta.0';
|
||||
|
||||
window.onerror = (message, file, line) => {
|
||||
if (typeof Blockbench != 'undefined' && Blockbench.setup_successful) return;
|
||||
@ -144,40 +144,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="toolbar_edit">
|
||||
<dialog class="dialog draggable" id="toolbar_edit">
|
||||
<div class="dialog_handle tl">dialog.toolbar_edit.title</div>
|
||||
|
||||
<ul class="bar" id="bar_items_current" v-sortable="{onChoose: choose, onUpdate: sort, onEnd: drop, animation: 160 }">
|
||||
<li v-for="item in currentBar" v-bind:title="item.name" :key="item.id||item">
|
||||
<div v-if="typeof item === 'string'" class="toolbar_separator"></div>
|
||||
<div v-else class="tool">
|
||||
<div class="tooltip">{{item.name + (BARS.condition(item.condition) ? '' : ' (' + tl('dialog.toolbar_edit.hidden') + ')' )}}</div>
|
||||
<span class="icon_wrapper" v-bind:style="{opacity: BARS.condition(item.condition) ? 1 : 0.4}" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="dialog_content">
|
||||
<ul class="bar" id="bar_items_current" v-sortable="{onChoose: choose, onUpdate: sort, onEnd: drop, animation: 160 }">
|
||||
<li v-for="item in currentBar" v-bind:title="item.name" :key="item.id||item">
|
||||
<div v-if="typeof item === 'string'" class="toolbar_separator" :class="{border: item[0] == '_', spacer: item[0] == '+', linebreak: item[0] == '#'}"></div>
|
||||
<div v-else class="tool">
|
||||
<div class="tooltip">{{item.name + (BARS.condition(item.condition) ? '' : ' (' + tl('dialog.toolbar_edit.hidden') + ')' )}}</div>
|
||||
<span class="icon_wrapper" v-bind:style="{opacity: BARS.condition(item.condition) ? 1 : 0.4}" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="tl small_text subtle">dialog.toolbar_edit.hidden_tools</p>
|
||||
<p class="tl small_text subtle">dialog.toolbar_edit.hidden_tools</p>
|
||||
|
||||
<div class="bar" style="margin: 4px 0;">
|
||||
<search-bar v-model="search_term"></search-bar>
|
||||
</div>
|
||||
|
||||
<ul class="list" id="bar_item_list">
|
||||
<li v-for="item in searchedBarItems" v-on:click="addItem(item)" :class="{separator_item: item.type == 'separator'}">
|
||||
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
|
||||
<div class="icon_wrapper add"><i class="material-icons">add</i></div>
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="bar" style="margin: 4px 0;">
|
||||
<search-bar v-model="search_term"></search-bar>
|
||||
</div>
|
||||
|
||||
<ul class="list" id="bar_item_list">
|
||||
<li v-for="item in searchedBarItems" v-on:click="addItem(item)">
|
||||
<div class="icon_wrapper normal" v-html="Blockbench.getIconNode(item.icon, item.color).outerHTML"></div>
|
||||
<div class="icon_wrapper add"><i class="material-icons">add</i></div>
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="dialog_bar button_bar">
|
||||
<button type="button" class="cancel_btn confirm_btn uc_btn tl" onclick="hideDialog();">dialog.close</button>
|
||||
</div>
|
||||
<div class="dialog_close_button" onclick="hideDialog();"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="entity_import">
|
||||
<dialog class="dialog draggable" id="entity_import">
|
||||
<div class="dialog_handle tl">dialog.entitylist.title</div>
|
||||
<div class="dialog_bar narrow tl">dialog.entitylist.text</div>
|
||||
<div class="search_bar">
|
||||
@ -200,7 +203,7 @@
|
||||
<div class="dialog_close_button" onclick="hideDialog();BarItems.close_project.click()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="image_extruder">
|
||||
<dialog class="dialog draggable" id="image_extruder">
|
||||
<div class="dialog_handle tl">dialog.extrude.title</div>
|
||||
<h1></h1>
|
||||
|
||||
@ -231,7 +234,7 @@
|
||||
<div class="dialog_close_button" onclick="hideDialog()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="scaling">
|
||||
<dialog class="dialog draggable" id="scaling">
|
||||
<div class="dialog_handle tl">dialog.scale.title</div>
|
||||
|
||||
<label class="tl">dialog.scale.axis</label>
|
||||
@ -279,7 +282,7 @@
|
||||
<div class="dialog_close_button" onclick="cancelScaleAll()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="create_preset">
|
||||
<dialog class="dialog draggable" id="create_preset">
|
||||
<div class="dialog_handle tl">dialog.display_preset.title</div>
|
||||
<div class="dialog_bar tl">dialog.display_preset.message</div>
|
||||
<div class="dialog_bar">
|
||||
@ -327,185 +330,6 @@
|
||||
<div class="dialog_close_button" onclick="hideDialog()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="settings">
|
||||
<div class="dialog_handle tl">menu.file.preferences</div>
|
||||
<div class="dialog_bar borderless tab_bar" id="settings_tab_bar">
|
||||
<div class="tl tab open" id="setting" onclick="setSettingsTab('setting')">dialog.settings.settings</div>
|
||||
<div class="tl tab" id="keybindings" onclick="setSettingsTab('keybindings')">dialog.settings.keybinds</div>
|
||||
<div class="tl tab" id="layout_settings" onclick="setSettingsTab('layout_settings')">dialog.settings.theme</div>
|
||||
<div class="tl tab" id="credits" onclick="setSettingsTab('credits')">dialog.settings.about</div>
|
||||
</div>
|
||||
|
||||
<div id="setting" class="tab_content">
|
||||
<h2 class="tl i_b">dialog.settings.settings</h2>
|
||||
<div class="bar next_to_title" id="settings_title_bar"></div>
|
||||
|
||||
<div class="search_bar">
|
||||
<input type="text" class="dark_bordered" id="settings_search_bar" oninput="Settings.updateSearch()">
|
||||
<i class="material-icons" id="settings_search_bar_icon">search</i>
|
||||
</div>
|
||||
|
||||
<ul id="settingslist">
|
||||
|
||||
<li v-for="category in structure" v-if="!category.hidden">
|
||||
<h3 v-on:click="toggleCategory(category)">
|
||||
<i class="material-icons settings_expand_icon">{{ category.open ? 'expand_more' : 'navigate_next' }}</i>
|
||||
{{ category.name }}
|
||||
</h3>
|
||||
<ul v-if="category.open">
|
||||
|
||||
<li v-for="(setting, key) in category.items" v-if="Condition(setting.condition)" v-on="setting.click ? {click: setting.click} : {}">
|
||||
<template v-if="setting.type === 'number'">
|
||||
<div class="setting_element"><input type="number" v-model.number="setting.value" :min="setting.min" :max="setting.max" :step="setting.step" v-on:input="saveSettings()"></div>
|
||||
</template>
|
||||
<template v-else-if="setting.type === 'click'">
|
||||
<div class="setting_element setting_icon" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
|
||||
</template>
|
||||
<template v-else-if="setting.type == 'toggle'"><!--TOGGLE-->
|
||||
<div class="setting_element"><input type="checkbox" v-model="setting.value" v-bind:id="'setting_'+key" v-on:click="saveSettings()"></div>
|
||||
</template>
|
||||
|
||||
<label class="setting_label" v-bind:for="'setting_'+key">
|
||||
<div class="setting_name">{{ setting.name }}</div>
|
||||
<div class="setting_description">{{ setting.description }}</div>
|
||||
</label>
|
||||
|
||||
<template v-if="setting.type === 'text'">
|
||||
<input type="text" class="dark_bordered" style="width: 96%" v-model="setting.value" v-on:input="saveSettings()">
|
||||
</template>
|
||||
|
||||
<template v-if="setting.type === 'password'">
|
||||
<input :type="setting.hidden ? 'password' : 'text'" class="dark_bordered" style="width: calc(96% - 28px);" v-model="setting.value" v-on:input="saveSettings()">
|
||||
<div class="password_toggle" @click="setting.hidden = !setting.hidden;">
|
||||
<i class="fas fa-eye-slash" v-if="setting.hidden"></i>
|
||||
<i class="fas fa-eye" v-else></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="setting.type === 'select'">
|
||||
<div class="bar_select">
|
||||
<select v-model="setting.value">
|
||||
<option v-for="(text, id) in setting.options" v-bind:value="id">{{ text }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="keybindings" class="hidden tab_content">
|
||||
<h2 class="tl i_b">dialog.settings.keybinds</h2>
|
||||
<div class="bar next_to_title" id="keybinds_title_bar"></div>
|
||||
|
||||
<div class="search_bar">
|
||||
<input type="text" class="dark_bordered" id="keybind_search_bar" oninput="Keybinds.updateSearch()">
|
||||
<i class="material-icons" id="keybind_search_bar_icon">search</i>
|
||||
</div>
|
||||
|
||||
<ul id="keybindlist">
|
||||
<li v-for="category in structure" v-if="!category.hidden">
|
||||
<h3 v-on:click="toggleCategory(category)">
|
||||
<i class="material-icons f_left settings_expand_icon">{{ category.open ? 'expand_more' : 'navigate_next' }}</i>
|
||||
{{ category.name }}
|
||||
<i class="material-icons f_right" v-if="category.conflict" style="color: var(--color-close);">fiber_manual_record</i>
|
||||
</h3>
|
||||
<ul v-if="category.open">
|
||||
<li v-for="action in category.actions">
|
||||
<div v-bind:title="action.description">{{action.name}}</div>
|
||||
<div class="keybindslot" :class="{conflict: action.keybind && action.keybind.conflict}" @click.stop="record(action)">{{ action.keybind ? action.keybind.label : '' }}</div>
|
||||
<div class="tool" v-on:click="reset(action)">
|
||||
<div class="tooltip tl">keybindings.reset</div>
|
||||
<i class="material-icons">replay</i>
|
||||
</div>
|
||||
<div class="tool" v-on:click="clear(action)">
|
||||
<div class="tooltip tl">keybindings.clear</div>
|
||||
<i class="material-icons">clear</i>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="layout_settings" class="hidden tab_content">
|
||||
<h2 class="tl i_b">dialog.settings.theme</h2>
|
||||
<div class="bar next_to_title" id="layout_title_bar"></div>
|
||||
<div class="y_scrollable" id="theme_editor">
|
||||
<div id="color_wrapper">
|
||||
<div class="color_field" v-for="(color, key) in colors" :id="'color_field_' + key">
|
||||
<div class="layout_color_preview" :style="{'background-color': color}" class="color_input"></div>
|
||||
<div class="desc">
|
||||
<h4>{{ tl('layout.color.'+key) }}</h4>
|
||||
<p>{{ tl('layout.color.'+key+'.desc') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog_bar">
|
||||
<label class="name_space_left tl" for="layout_font_main">layout.font.main</label>
|
||||
<input style="font-family: var(--font-main)" type="text" class="half dark_bordered" id="layout_font_main" v-model="main_font">
|
||||
</div>
|
||||
|
||||
<div class="dialog_bar">
|
||||
<label class="name_space_left tl" for="layout_font_headline">layout.font.headline</label>
|
||||
<input style="font-family: var(--font-headline)" type="text" class="half dark_bordered" id="layout_font_headline" v-model="headline_font">
|
||||
</div>
|
||||
<div class="dialog_bar">
|
||||
<label class="name_space_left tl" for="layout_font_cpde">layout.font.code</label>
|
||||
<input style="font-family: var(--font-code)" type="text" class="half dark_bordered" id="layout_font_cpde" v-model="code_font">
|
||||
</div>
|
||||
<h4 class="tl i_b">layout.css</h4>
|
||||
<div id="css_editor">
|
||||
<vue-prism-editor v-model="css" language="css" :line-numbers="true" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="credits" class="hidden tab_content">
|
||||
<h2 class="tl i_b">dialog.settings.about</h2>
|
||||
<div id="about_page_title">
|
||||
<img src="assets/logo_text_white.svg" width="240px">
|
||||
</div>
|
||||
<p><b class="tl">about.version</b> <span id="version_tag"></span></p>
|
||||
<p><b class="tl">about.creator</b> JannisX11</p>
|
||||
<p><b class="tl">about.website</b> <a class="open-in-browser" href="https://blockbench.net">blockbench.net</a></p>
|
||||
<p><b class="tl">about.repository</b> <a class="open-in-browser" href="https://github.com/JannisX11/blockbench">github.com/JannisX11/blockbench</a></p>
|
||||
<p class="local_only tl">about.electron</p>
|
||||
<p class="tl">about.vertex_snap</p>
|
||||
<p><b class="tl">about.icons</b> <a href="https://material.io/icons/" class="open-in-browser">material.io/icons</a> & <a href="https://fontawesome.io/icons/" class="open-in-browser">fontawesome</a></p>
|
||||
<p><b class="tl">about.libraries</b>
|
||||
<a class="open-in-browser" href="https://vuejs.org">Vue</a>,
|
||||
<a class="open-in-browser" href="https://github.com/weibangtuo/vue-tree">Vue Tree</a>,
|
||||
<a class="open-in-browser" href="https://github.com/sagalbot/vue-sortable">Vue Sortable</a>,
|
||||
<a class="open-in-browser" href="https://threejs.org">ThreeJS</a>,
|
||||
<a class="open-in-browser" href="https://github.com/lo-th/fullik">Full IK</a>,
|
||||
<a class="open-in-browser" href="https://github.com/oliver-moran/jimp">Jimp</a>,
|
||||
<a class="open-in-browser" href="https://bgrins.github.io/spectrum">Spectrum</a>,
|
||||
<a class="open-in-browser" href="https://github.com/jnordberg/gif.js">gif.js</a>,
|
||||
<a class="open-in-browser" href="https://stuk.github.io/jszip/">JSZip</a>,
|
||||
<a class="open-in-browser" href="https://github.com/rotemdan/lzutf8.js">LZ-UTF8</a>,
|
||||
<a class="open-in-browser" href="https://jquery.com">jQuery</a>,
|
||||
<a class="open-in-browser" href="https://jqueryui.com">jQuery UI</a>,
|
||||
<a class="open-in-browser" href="https://github.com/furf/jquery-ui-touch-punch">jQuery UI Touch Punch</a>,
|
||||
<a class="open-in-browser" href="https://github.com/eligrey/FileSaver.js">FileSaver.js</a>,
|
||||
<a class="open-in-browser" href="https://peerjs.com">PeerJS</a>,
|
||||
<a class="open-in-browser" href="https://github.com/markedjs/marked">Marked</a>,
|
||||
<a class="open-in-browser" href="https://prismjs.com">Prism</a>,
|
||||
<a class="open-in-browser" href="https://github.com/koca/vue-prism-editor">Vue Prism Editor</a>,
|
||||
<a class="open-in-browser" href="https://github.com/JannisX11/molangjs">MolangJS</a>,
|
||||
<a class="open-in-browser" href="https://github.com/JannisX11/wintersky">Wintersky</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="dialog_bar button_bar" hidden>
|
||||
<button type="button" class="confirm_btn cancel_btn tl" onclick="Settings.save()">dialog.close</button>
|
||||
</div>
|
||||
<div class="dialog_close_button" onclick="Settings.save()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable" id="uv_dialog">
|
||||
<div class="dialog_handle tl">uv_editor.title</div>
|
||||
<div class="dialog_bar borderless tab_bar" id="uv_tab_bar">
|
||||
@ -534,7 +358,7 @@
|
||||
<div class="dialog_close_button" onclick="hideDialog()"><i class="material-icons">clear</i></div>
|
||||
</dialog>
|
||||
|
||||
<dialog class="dialog draggable paddinged" id="text_input">
|
||||
<dialog class="dialog draggable" id="text_input">
|
||||
<div class="dialog_handle tl">dialog.input.title</div>
|
||||
|
||||
<div class="dialog_bar">
|
||||
|
@ -280,13 +280,13 @@ class Keyframe {
|
||||
Timeline.dragging_keyframes = false
|
||||
return this;
|
||||
}
|
||||
if (!event || (!event.shiftKey && !event.ctrlOrCmd)) {
|
||||
if (!event || (!event.shiftKey && !event.ctrlOrCmd && !Pressing.overrides.ctrl && !Pressing.overrides.shift)) {
|
||||
Timeline.selected.forEach(function(kf) {
|
||||
kf.selected = false
|
||||
})
|
||||
Timeline.selected.empty()
|
||||
}
|
||||
if (event && event.shiftKey && Timeline.selected.length) {
|
||||
if (event && (event.shiftKey || Pressing.overrides.shift) && Timeline.selected.length) {
|
||||
var last = Timeline.selected[Timeline.selected.length-1]
|
||||
if (last && last.channel === scope.channel && last.animator == scope.animator) {
|
||||
Timeline.keyframes.forEach((kf) => {
|
||||
@ -412,6 +412,7 @@ class Keyframe {
|
||||
])
|
||||
new Property(Keyframe, 'number', 'time')
|
||||
new Property(Keyframe, 'number', 'color', {default: -1})
|
||||
new Property(Keyframe, 'boolean', 'uniform', {condition: keyframe => keyframe.channel == 'scale', default: true})
|
||||
new Property(Keyframe, 'string', 'interpolation', {default: 'linear'})
|
||||
Keyframe.selected = [];
|
||||
Keyframe.interpolation = {
|
||||
@ -490,8 +491,8 @@ BARS.defineActions(function() {
|
||||
if (Toolbox.selected.id == 'rotate_tool' && animator.channels.includes('rotation')) channel = 'rotation';
|
||||
if (Toolbox.selected.id == 'move_tool' && animator.channels.includes('position')) channel = 'position';
|
||||
if (Toolbox.selected.id == 'resize_tool' && animator.channels.includes('scale')) channel = 'scale';
|
||||
animator.createKeyframe((event && event.shiftKey) ? {} : null, Timeline.time, channel, true);
|
||||
if (event && event.shiftKey) {
|
||||
animator.createKeyframe((event && (event.shiftKey || Pressing.overrides.shift)) ? {} : null, Timeline.time, channel, true);
|
||||
if (event && (event.shiftKey || Pressing.overrides.shift)) {
|
||||
Animator.preview();
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ const Timeline = {
|
||||
e.clientX - R.panel_offset[0],
|
||||
e.clientY - R.panel_offset[1],
|
||||
]
|
||||
if (e.shiftKey) {
|
||||
if (e.shiftKey || Pressing.overrides.shift) {
|
||||
Timeline.selector.selected_before = Timeline.selected.slice();
|
||||
}
|
||||
R.selecting = true;
|
||||
@ -268,7 +268,7 @@ const Timeline = {
|
||||
|
||||
let offset = e.clientX - $('#timeline_time').offset().left;
|
||||
let time = Math.clamp(offset / Timeline.vue._data.size, 0, Infinity);
|
||||
if (!e.ctrlOrCmd) time = Timeline.snapTime(time);
|
||||
if (!e && !Pressing.overrides.ctrl) time = Timeline.snapTime(time);
|
||||
Timeline.setTime(time);
|
||||
Animator.preview();
|
||||
}
|
||||
@ -279,7 +279,7 @@ const Timeline = {
|
||||
convertTouchEvent(e);
|
||||
let offset = e.clientX - $('#timeline_time').offset().left;
|
||||
let time = Math.clamp(offset / Timeline.vue._data.size, 0, Infinity);
|
||||
if (!e.ctrlOrCmd) time = Timeline.snapTime(time);
|
||||
if (!e.ctrlOrCmd && !Pressing.overrides.ctrl) time = Timeline.snapTime(time);
|
||||
if (Timeline.time != time) {
|
||||
Timeline.setTime(time)
|
||||
Animator.preview()
|
||||
@ -750,10 +750,10 @@ onVueSetup(function() {
|
||||
dragging_restriction;
|
||||
originalValue;
|
||||
previousValue = 0;
|
||||
time_stretching = !Timeline.vue.graph_editor_open && e1.ctrlOrCmd && Timeline.selected.length > 1;
|
||||
time_stretching = !Timeline.vue.graph_editor_open && (e1.ctrlOrCmd || Pressing.overrides.ctrl) && Timeline.selected.length > 1;
|
||||
values_changed = false;
|
||||
|
||||
if (!clicked.selected && !e1.shiftKey && Timeline.selected.length != 0) {
|
||||
if (!clicked.selected && !e1.shiftKey && !Pressing.overrides.shift && Timeline.selected.length != 0) {
|
||||
clicked.select()
|
||||
} else if (clicked && !clicked.selected) {
|
||||
clicked.select({shiftKey: true})
|
||||
@ -824,7 +824,7 @@ onVueSetup(function() {
|
||||
let value_diff = 0;
|
||||
if (Timeline.vue.graph_editor_open) {
|
||||
value = -offset[1] / Timeline.vue.graph_size;
|
||||
var round_num = canvasGridSize(e2.shiftKey, e2.ctrlOrCmd);
|
||||
var round_num = canvasGridSize(e2.shiftKey || Pressing.overrides.shift, e2.ctrlOrCmd || Pressing.overrides.ctrl);
|
||||
if (Toolbox.selected.id === 'resize_tool') {
|
||||
round_num *= 0.1;
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ const Blockbench = {
|
||||
}
|
||||
|
||||
var jq_dialog = $(`
|
||||
<dialog class="dialog paddinged" style="width: auto;" id="message_box">
|
||||
<dialog class="dialog" style="width: auto;" id="message_box">
|
||||
<div class="dialog_handle">${tl(options.title)}</div>
|
||||
<div class="dialog_close_button" onclick="open_interface.cancel()"><i class="material-icons">clear</i></div>
|
||||
</dialog>`)
|
||||
|
@ -36,12 +36,6 @@ var Prop = {
|
||||
const mouse_pos = {x:0,y:0}
|
||||
const sort_collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
|
||||
|
||||
function onVueSetup(func) {
|
||||
if (!onVueSetup.funcs) {
|
||||
onVueSetup.funcs = []
|
||||
}
|
||||
onVueSetup.funcs.push(func)
|
||||
}
|
||||
function canvasGridSize(shift, ctrl) {
|
||||
if (!shift && !ctrl) {
|
||||
return 16 / Math.clamp(settings.edit_size.value, 1, 512)
|
||||
@ -232,6 +226,89 @@ const documentReady = new Promise((resolve, reject) => {
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
BARS.defineActions(() => {
|
||||
|
||||
new Action('about_window', {
|
||||
name: tl('dialog.settings.about') + '...',
|
||||
icon: 'info',
|
||||
category: 'blockbench',
|
||||
click: function () {
|
||||
const data = {
|
||||
isApp,
|
||||
version_label: Blockbench.version
|
||||
};
|
||||
jQuery.ajax({
|
||||
url: 'https://api.github.com/repos/JannisX11/blockbench/releases/latest',
|
||||
cache: false,
|
||||
type: 'GET',
|
||||
success(release) {
|
||||
let v = release.tag_name.replace(/^v/, '');
|
||||
if (compareVersions(v, Blockbench.version)) {
|
||||
data.version_label = `${Blockbench.version} (${tl('about.version.update_available', [v])})`;
|
||||
} else if (compareVersions(Blockbench.version, v)) {
|
||||
data.version_label = `${Blockbench.version} (Pre-release)`;
|
||||
} else {
|
||||
data.version_label = `${Blockbench.version} (${tl('about.version.up_to_date')}😄)`;
|
||||
}
|
||||
},
|
||||
error(err) {}
|
||||
})
|
||||
|
||||
new Dialog({
|
||||
id: 'about',
|
||||
title: 'dialog.settings.about',
|
||||
width: 600,
|
||||
singleButton: true,
|
||||
title_menu: new Menu([
|
||||
'settings_window',
|
||||
'keybindings_window',
|
||||
'theme_window',
|
||||
'about_window',
|
||||
]),
|
||||
component: {
|
||||
data() {return data},
|
||||
template: `
|
||||
<div>
|
||||
<div id="about_page_title">
|
||||
<img src="assets/logo_text_white.svg" width="240px">
|
||||
</div>
|
||||
<p><b>${tl('about.version')}</b> <span>{{ version_label }}</span></p>
|
||||
<p><b>${tl('about.creator')}</b> JannisX11</p>
|
||||
<p><b>${tl('about.website')}</b> <a class="open-in-browser" href="https://blockbench.net">blockbench.net</a></p>
|
||||
<p><b>${tl('about.repository')}</b> <a class="open-in-browser" href="https://github.com/JannisX11/blockbench">github.com/JannisX11/blockbench</a></p>
|
||||
<p>${tl('about.vertex_snap')}</p>
|
||||
<p><b>${tl('about.icons')}</b> <a href="https://material.io/icons/" class="open-in-browser">material.io/icons</a> & <a href="https://fontawesome.io/icons/" class="open-in-browser">fontawesome</a></p>
|
||||
<p><b>${tl('about.libraries')}</b>
|
||||
<a class="open-in-browser" href="https://electronjs.org">Electron</a>,
|
||||
<a class="open-in-browser" href="https://vuejs.org">Vue</a>,
|
||||
<a class="open-in-browser" href="https://github.com/weibangtuo/vue-tree">Vue Tree</a>,
|
||||
<a class="open-in-browser" href="https://github.com/sagalbot/vue-sortable">Vue Sortable</a>,
|
||||
<a class="open-in-browser" href="https://threejs.org">ThreeJS</a>,
|
||||
<a class="open-in-browser" href="https://github.com/lo-th/fullik">Full IK</a>,
|
||||
<a class="open-in-browser" href="https://github.com/oliver-moran/jimp">Jimp</a>,
|
||||
<a class="open-in-browser" href="https://bgrins.github.io/spectrum">Spectrum</a>,
|
||||
<a class="open-in-browser" href="https://github.com/jnordberg/gif.js">gif.js</a>,
|
||||
<a class="open-in-browser" href="https://stuk.github.io/jszip/">JSZip</a>,
|
||||
<a class="open-in-browser" href="https://github.com/rotemdan/lzutf8.js">LZ-UTF8</a>,
|
||||
<a class="open-in-browser" href="https://jquery.com">jQuery</a>,
|
||||
<a class="open-in-browser" href="https://jqueryui.com">jQuery UI</a>,
|
||||
<a class="open-in-browser" href="https://github.com/furf/jquery-ui-touch-punch">jQuery UI Touch Punch</a>,
|
||||
<a class="open-in-browser" href="https://github.com/eligrey/FileSaver.js">FileSaver.js</a>,
|
||||
<a class="open-in-browser" href="https://peerjs.com">PeerJS</a>,
|
||||
<a class="open-in-browser" href="https://github.com/markedjs/marked">Marked</a>,
|
||||
<a class="open-in-browser" href="https://prismjs.com">Prism</a>,
|
||||
<a class="open-in-browser" href="https://github.com/koca/vue-prism-editor">Vue Prism Editor</a>,
|
||||
<a class="open-in-browser" href="https://github.com/JannisX11/molangjs">MolangJS</a>,
|
||||
<a class="open-in-browser" href="https://github.com/JannisX11/wintersky">Wintersky</a>
|
||||
</p>
|
||||
</div>`
|
||||
}
|
||||
}).show()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const entityMode = {
|
||||
hardcodes: JSON.parse('{"geometry.chicken":{"body":{"rotation":[90,0,0]}},"geometry.llama":{"chest1":{"rotation":[0,90,0]},"chest2":{"rotation":[0,90,0]},"body":{"rotation":[90,0,0]}},"geometry.cow":{"body":{"rotation":[90,0,0]}},"geometry.sheep.sheared":{"body":{"rotation":[90,0,0]}},"geometry.sheep":{"body":{"rotation":[90,0,0]}},"geometry.phantom":{"body":{"rotation":[0,0,0]},"wing0":{"rotation":[0,0,5.7]},"wingtip0":{"rotation":[0,0,5.7]},"wing1":{"rotation":[0,0,-5.7]},"wingtip1":{"rotation":[0,0,-5.7]},"head":{"rotation":[11.5,0,0]},"tail":{"rotation":[0,0,0]},"tailtip":{"rotation":[0,0,0]}},"geometry.pig":{"body":{"rotation":[90,0,0]}},"geometry.ocelot":{"body":{"rotation":[90,0,0]},"tail1":{"rotation":[90,0,0]},"tail2":{"rotation":[90,0,0]}},"geometry.cat":{"body":{"rotation":[90,0,0]},"tail1":{"rotation":[90,0,0]},"tail2":{"rotation":[90,0,0]}},"geometry.turtle":{"eggbelly":{"rotation":[90,0,0]},"body":{"rotation":[90,0,0]}},"geometry.villager.witch":{"hat2":{"rotation":[-3,0,1.5]},"hat3":{"rotation":[-6,0,3]},"hat4":{"rotation":[-12,0,6]}},"geometry.pufferfish.mid":{"spines_top_front":{"rotation":[45,0,0]},"spines_top_back":{"rotation":[-45,0,0]},"spines_bottom_front":{"rotation":[-45,0,0]},"spines_bottom_back":{"rotation":[45,0,0]},"spines_left_front":{"rotation":[0,45,0]},"spines_left_back":{"rotation":[0,-45,0]},"spines_right_front":{"rotation":[0,-45,0]},"spines_right_back":{"rotation":[0,45,0]}},"geometry.pufferfish.large":{"spines_top_front":{"rotation":[45,0,0]},"spines_top_back":{"rotation":[-45,0,0]},"spines_bottom_front":{"rotation":[-45,0,0]},"spines_bottom_back":{"rotation":[45,0,0]},"spines_left_front":{"rotation":[0,45,0]},"spines_left_back":{"rotation":[0,-45,0]},"spines_right_front":{"rotation":[0,-45,0]},"spines_right_back":{"rotation":[0,45,0]}},"geometry.tropicalfish_a":{"leftFin":{"rotation":[0,-35,0]},"rightFin":{"rotation":[0,35,0]}},"geometry.tropicalfish_b":{"leftFin":{"rotation":[0,-35,0]},"rightFin":{"rotation":[0,35,0]}}}')
|
||||
}
|
||||
|
@ -1059,7 +1059,7 @@ class Toolbar {
|
||||
this.condition_cache = [];
|
||||
|
||||
// items the toolbar could not load on startup, most likely from plugins (stored as IDs)
|
||||
this.postload = undefined;
|
||||
this.postload = null;
|
||||
// object storing initial position of actions
|
||||
// if a property with a given position is set, then this slot is occupied
|
||||
// and the associated object (action) can effectively be used with indexOf on children
|
||||
@ -1100,9 +1100,14 @@ class Toolbar {
|
||||
content.children().detach()
|
||||
for (var itemPosition = 0; itemPosition < items.length; itemPosition++) {
|
||||
var itemId = items[itemPosition];
|
||||
if (typeof itemId === 'string' && itemId.substr(0, 1) === '_') {
|
||||
content.append('<div class="toolbar_separator"></div>');
|
||||
this.children.push('_' + guid().substr(0,8));
|
||||
if (typeof itemId === 'string' && itemId.match(/^[_+#]/)) {
|
||||
let char = itemId.substr(0, 1);
|
||||
content.append(`<div class="toolbar_separator ${char == '_' ? 'border' : (char == '+' ? 'spacer' : 'linebreak')}"></div>`);
|
||||
this.children.push(char + guid().substr(0,8));
|
||||
|
||||
if (char === '+') content[0].style.display = 'flex';
|
||||
if (char === '#') content[0].style.display = 'block';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1201,7 +1206,7 @@ class Toolbar {
|
||||
}
|
||||
}
|
||||
if (this.postload.length == 0) {
|
||||
this.postload = undefined; // array obj no longer needed
|
||||
this.postload = null; // array obj no longer needed
|
||||
}
|
||||
}
|
||||
|
||||
@ -1223,8 +1228,11 @@ class Toolbar {
|
||||
|
||||
var content = $(this.node).find('.content')
|
||||
content.find('> .tool').detach()
|
||||
var separators = content.find('> .toolbar_separator').detach()
|
||||
var sep_nr = 0;
|
||||
var separators = {
|
||||
border: content.find('> .toolbar_separator.border').detach().toArray(),
|
||||
spacer: content.find('> .toolbar_separator.spacer').detach().toArray(),
|
||||
linebreak: content.find('> .toolbar_separator.linebreak').detach().toArray(),
|
||||
}
|
||||
|
||||
this.children.forEach(function(item, i) {
|
||||
if (typeof item === 'string') {
|
||||
@ -1232,13 +1240,18 @@ class Toolbar {
|
||||
if (last.length === 0 || last.hasClass('toolbar_separator') || i == scope.children.length-1) {
|
||||
return this;
|
||||
}
|
||||
var sep = separators[sep_nr]
|
||||
let type = item[0] == '_' ? 'border' : (item[0] == '+' ? 'spacer' : 'linebreak');
|
||||
let sep = separators[type].shift();
|
||||
if (sep) {
|
||||
content.append(sep)
|
||||
sep_nr++;
|
||||
content.append(sep);
|
||||
} else {
|
||||
content.append('<div class="toolbar_separator"></div>')
|
||||
let separator = document.createElement('div');
|
||||
separator.className = `toolbar_separator ${type}`;
|
||||
content.append(separator);
|
||||
}
|
||||
if (item[0] === '+') content[0].style.display = 'flex';
|
||||
if (item[0] === '#') content[0].style.display = 'block';
|
||||
|
||||
} else if (typeof item === 'object') {
|
||||
if (scope.condition_cache[i]) {
|
||||
content.append(item.getNode())
|
||||
@ -1320,6 +1333,10 @@ const BARS = {
|
||||
category: 'navigate',
|
||||
keybind: new Keybind({key: 1, shift: true})
|
||||
})
|
||||
new KeybindItem('preview_area_select', {
|
||||
category: 'navigate',
|
||||
keybind: new Keybind({key: 1, ctrl: true, shift: null})
|
||||
})
|
||||
|
||||
new KeybindItem('confirm', {
|
||||
category: 'navigate',
|
||||
@ -1431,23 +1448,6 @@ const BARS = {
|
||||
shell.openPath(app.getPath('userData')+osfs+'backups')
|
||||
}
|
||||
})
|
||||
new Action('settings_window', {
|
||||
icon: 'settings',
|
||||
category: 'blockbench',
|
||||
click: function () {Settings.open()}
|
||||
})
|
||||
new Action('keybindings_window', {
|
||||
name: tl('dialog.settings.keybinds') + '...',
|
||||
icon: 'keyboard',
|
||||
category: 'blockbench',
|
||||
click: function () {Settings.open({tab: 'keybindings'})}
|
||||
})
|
||||
new Action('theme_window', {
|
||||
name: tl('dialog.settings.theme') + '...',
|
||||
icon: 'style',
|
||||
category: 'blockbench',
|
||||
click: function () {Settings.open({tab: 'layout_settings'})}
|
||||
})
|
||||
new Action('reload', {
|
||||
icon: 'refresh',
|
||||
category: 'file',
|
||||
@ -1913,11 +1913,26 @@ const BARS = {
|
||||
computed: {
|
||||
searchedBarItems() {
|
||||
var name = this.search_term.toUpperCase()
|
||||
var list = [{
|
||||
icon: 'bookmark',
|
||||
name: tl('data.separator'),
|
||||
type: 'separator'
|
||||
}]
|
||||
var list = [
|
||||
{
|
||||
icon: 'fa-grip-lines-vertical',
|
||||
name: tl('data.separator'),
|
||||
type: 'separator',
|
||||
separator_code: '_'
|
||||
},
|
||||
{
|
||||
icon: 'space_bar',
|
||||
name: tl('data.separator.spacer'),
|
||||
type: 'separator',
|
||||
separator_code: '+'
|
||||
},
|
||||
{
|
||||
icon: 'fa-paragraph',
|
||||
name: tl('data.separator.linebreak'),
|
||||
type: 'separator',
|
||||
separator_code: '#'
|
||||
}
|
||||
]
|
||||
for (var key in BarItems) {
|
||||
var item = BarItems[key]
|
||||
if (name.length == 0 ||
|
||||
@ -1935,35 +1950,39 @@ const BARS = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sort: function(event) {
|
||||
sort(event) {
|
||||
var item = this.currentBar.splice(event.oldIndex, 1)[0]
|
||||
this.currentBar.splice(event.newIndex, 0, item)
|
||||
this.update();
|
||||
},
|
||||
drop: function(event) {
|
||||
drop(event) {
|
||||
var scope = this;
|
||||
var index = event.oldIndex
|
||||
$('#bar_items_current .tooltip').css('display', '')
|
||||
setTimeout(() => {
|
||||
if ($('#bar_items_current:hover').length === 0) {
|
||||
var item = scope.currentBar.splice(event.oldIndex, 1)[0]
|
||||
item.toolbars.remove(BARS.editing_bar)
|
||||
scope.update()
|
||||
var item = scope.currentBar.splice(event.newIndex, 1)[0];
|
||||
if (item instanceof BarItem) item.toolbars.remove(BARS.editing_bar);
|
||||
scope.update();
|
||||
}
|
||||
}, 30)
|
||||
},
|
||||
choose: function(event) {
|
||||
choose() {
|
||||
$('#bar_items_current .tooltip').css('display', 'none')
|
||||
},
|
||||
update: function() {
|
||||
update() {
|
||||
BARS.editing_bar.update(true).save();
|
||||
},
|
||||
addItem: function(item) {
|
||||
addItem(item) {
|
||||
if (item.type === 'separator') {
|
||||
item = '_'
|
||||
item = item.separator_code;
|
||||
}
|
||||
if (item == '#' && BARS.editing_bar.children.find(c => typeof c == 'string' && c[0] == '+') ||
|
||||
item == '+' && BARS.editing_bar.children.find(c => typeof c == 'string' && c[0] == '#')
|
||||
) {
|
||||
Blockbench.showQuickMessage('dialog.toolbar_edit.incompatible_separators', 2000);
|
||||
} else {
|
||||
BARS.editing_bar.add(item);
|
||||
}
|
||||
BARS.editing_bar.add(item);
|
||||
// BARS.editing_bar.update().save(); already called in add()
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -2145,14 +2164,7 @@ const Keybinds = {
|
||||
actions: [],
|
||||
stored: {},
|
||||
extra: {},
|
||||
structure: {
|
||||
search_results: {
|
||||
name: tl('dialog.settings.search_results'),
|
||||
hidden: true,
|
||||
open: true,
|
||||
actions: {}
|
||||
}
|
||||
},
|
||||
structure: {},
|
||||
save() {
|
||||
localStorage.setItem('keybindings', JSON.stringify(Keybinds.stored))
|
||||
}
|
||||
|
@ -294,6 +294,85 @@ function buildComponent(dialog) {
|
||||
dialog.content_vue = new Vue(dialog.component).$mount(mount.get(0));
|
||||
}
|
||||
|
||||
class DialogSidebar {
|
||||
constructor(options) {
|
||||
this.open = true;
|
||||
this.pages = options.pages || {};
|
||||
this.page = options.page || Object.keys(this.pages)[0];
|
||||
this.actions = options.actions || {};
|
||||
this.onPageSwitch = options.onPageSwitch || null;
|
||||
}
|
||||
build() {
|
||||
if (!this.node) {
|
||||
this.node = document.createElement('div');
|
||||
this.node.className = 'dialog_sidebar';
|
||||
}
|
||||
|
||||
let page_list = document.createElement('ul');
|
||||
page_list.className = 'dialog_sidebar_pages';
|
||||
this.node.append(page_list);
|
||||
this.page_menu = {};
|
||||
for (let key in this.pages) {
|
||||
let li = document.createElement('li');
|
||||
li.textContent = this.pages[key];
|
||||
if (this.page == key) li.classList.add('selected');
|
||||
this.page_menu[key] = li;
|
||||
li.addEventListener('click', event => {
|
||||
this.setPage(key);
|
||||
})
|
||||
page_list.append(li);
|
||||
}
|
||||
|
||||
if (this.actions.length) {
|
||||
let action_list = document.createElement('ul');
|
||||
action_list.className = 'dialog_sidebar_actions';
|
||||
this.node.append(action_list);
|
||||
this.actions.forEach(action => {
|
||||
if (typeof action == 'string') {
|
||||
action = BarItems[action];
|
||||
}
|
||||
let copy;
|
||||
if (action instanceof Action) {
|
||||
copy = action.menu_node.cloneNode(true);
|
||||
copy.addEventListener('click', event => {
|
||||
action.trigger(event);
|
||||
})
|
||||
} else {
|
||||
copy = document.createElement('li');
|
||||
copy.title = action.description ? tl(action.description) : '';
|
||||
let icon = Blockbench.getIconNode(action.icon, action.color);
|
||||
let span = document.createElement('span');
|
||||
span.textContent = tl(action.name);
|
||||
copy.append(icon);
|
||||
copy.append(span);
|
||||
copy.addEventListener('click', event => {
|
||||
Blockbench.openLink('https://www.blockbench.net/wiki/blockbench/themes');
|
||||
})
|
||||
}
|
||||
action_list.append(copy);
|
||||
})
|
||||
}
|
||||
|
||||
this.toggle(this.open);
|
||||
|
||||
return this.node;
|
||||
}
|
||||
toggle(state = !this.open) {
|
||||
this.open = state;
|
||||
this.node.style.display = this.open ? 'flex' : 'none';
|
||||
if (this.node.parentElement) {
|
||||
this.node.parentElement.classList.toggle('has_sidebar', this.open);
|
||||
}
|
||||
}
|
||||
setPage(page) {
|
||||
this.page = page;
|
||||
if (this.onPageSwitch) this.onPageSwitch(page);
|
||||
for (let key in this.page_menu) {
|
||||
let li = this.page_menu[key];
|
||||
li.classList.toggle('selected', key == this.page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.Dialog = class Dialog {
|
||||
constructor(id, options) {
|
||||
@ -309,8 +388,10 @@ window.Dialog = class Dialog {
|
||||
this.component = options.component
|
||||
this.part_order = options.part_order || (options.form_first ? ['form', 'lines', 'component'] : ['lines', 'form', 'component'])
|
||||
|
||||
this.sidebar = options.sidebar ? new DialogSidebar(options.sidebar) : null;
|
||||
this.title_menu = options.title_menu || null;
|
||||
|
||||
this.width = options.width
|
||||
this.padding = options.padding != false;
|
||||
this.draggable = options.draggable
|
||||
this.singleButton = options.singleButton
|
||||
this.buttons = options.buttons instanceof Array ? options.buttons : (options.singleButton ? ['dialog.close'] : ['dialog.confirm', 'dialog.cancel'])
|
||||
@ -409,14 +490,45 @@ window.Dialog = class Dialog {
|
||||
this.hide();
|
||||
}
|
||||
build() {
|
||||
var jq_dialog = $(`<dialog class="dialog" id="${this.id}">
|
||||
<div class="dialog_handle">${tl(this.title)}</div>
|
||||
<content class="dialog_content"></content>
|
||||
</dialog>`)
|
||||
this.object = jq_dialog.get(0)
|
||||
this.max_label_width = 0;
|
||||
if (this.padding) this.object.classList.add('paddinged');
|
||||
this.object = document.createElement('dialog');
|
||||
this.object.className = 'dialog';
|
||||
this.object.id = this.id;
|
||||
|
||||
let handle = document.createElement('div');
|
||||
handle.className = 'dialog_handle';
|
||||
if (this.title_menu) {
|
||||
let menu_button = document.createElement('div');
|
||||
menu_button.className = 'dialog_menu_button';
|
||||
menu_button.append(Blockbench.getIconNode('menu'));
|
||||
menu_button.addEventListener('click', event => {
|
||||
this.title_menu.show(menu_button);
|
||||
})
|
||||
handle.append(menu_button);
|
||||
}
|
||||
let title = document.createElement('div');
|
||||
title.className = 'dialog_title';
|
||||
title.textContent = tl(this.title);
|
||||
handle.append(title);
|
||||
this.object.append(handle);
|
||||
|
||||
let jq_dialog = $(this.object);
|
||||
this.max_label_width = 0;
|
||||
|
||||
let wrapper = document.createElement('div');
|
||||
wrapper.className = 'dialog_wrapper';
|
||||
|
||||
let content = document.createElement('content');
|
||||
content.className = 'dialog_content';
|
||||
this.object.append(wrapper);
|
||||
|
||||
|
||||
if (this.sidebar) {
|
||||
let sidebar = this.sidebar.build();
|
||||
wrapper.append(sidebar);
|
||||
wrapper.classList.toggle('has_sidebar', this.sidebar.open);
|
||||
}
|
||||
|
||||
wrapper.append(content);
|
||||
|
||||
this.part_order.forEach(part => {
|
||||
if (part == 'form' && this.form) buildForm(this);
|
||||
@ -440,13 +552,14 @@ window.Dialog = class Dialog {
|
||||
})
|
||||
buttons[this.confirmIndex] && buttons[this.confirmIndex].addClass('confirm_btn')
|
||||
buttons[this.cancelIndex] && buttons[this.cancelIndex].addClass('cancel_btn')
|
||||
let bar = $('<div class="dialog_bar button_bar"></div>');
|
||||
jq_dialog.append(bar);
|
||||
let button_bar = $('<div class="dialog_bar button_bar"></div>');
|
||||
|
||||
buttons.forEach((button, i) => {
|
||||
if (i) bar.append(' ')
|
||||
bar.append(button)
|
||||
if (i) button_bar.append(' ')
|
||||
button_bar.append(button)
|
||||
})
|
||||
|
||||
wrapper.append(button_bar[0]);
|
||||
}
|
||||
|
||||
let close_button = document.createElement('div');
|
||||
|
@ -508,51 +508,6 @@ function hideDialog() {
|
||||
open_interface = false;
|
||||
Prop.active_panel = undefined
|
||||
}
|
||||
function setSettingsTab(tab) {
|
||||
$('#settings .tab.open').removeClass('open')
|
||||
$('#settings .tab#'+tab).addClass('open')
|
||||
$('#settings .tab_content').addClass('hidden')
|
||||
$('#settings .tab_content#'+tab).removeClass('hidden')
|
||||
if (tab === 'keybindings') {
|
||||
//Keybinds
|
||||
$('#keybindlist').css('max-height', (window.innerHeight - 420) +'px')
|
||||
$('#keybind_search_bar').focus()
|
||||
|
||||
} else if (tab === 'setting') {
|
||||
//Settings
|
||||
$('#settingslist').css('max-height', (window.innerHeight - 420) +'px')
|
||||
$('#settings_search_bar').focus()
|
||||
|
||||
} else if (tab === 'layout_settings') {
|
||||
//Layout
|
||||
$('#theme_editor').css('max-height', (window.innerHeight - 420) +'px')
|
||||
if (!CustomTheme.dialog_is_setup) CustomTheme.setupDialog()
|
||||
} else if (tab == 'credits') {
|
||||
// About
|
||||
|
||||
$('#version_tag').text(appVersion)
|
||||
if (isApp) {
|
||||
jQuery.ajax({
|
||||
url: 'https://api.github.com/repos/JannisX11/blockbench/releases/latest',
|
||||
cache: false,
|
||||
type: 'GET',
|
||||
success(release) {
|
||||
let v = release.tag_name.replace(/^v/, '');
|
||||
if (compareVersions(v, appVersion)) {
|
||||
$('#version_tag').text(`${appVersion} (${tl('about.version.update_available', [v])})`)
|
||||
} else if (compareVersions(appVersion, v)) {
|
||||
$('#version_tag').text(`${appVersion} (Pre-release)`)
|
||||
} else {
|
||||
$('#version_tag').text(`${appVersion} (${tl('about.version.up_to_date')}😄)`)
|
||||
}
|
||||
},
|
||||
error(err) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getStringWidth(string, size) {
|
||||
var a = $('<label style="position: absolute">'+string+'</label>')
|
||||
|
@ -88,7 +88,7 @@ class Keybind {
|
||||
Keybinds.structure[action.category].actions.push(action)
|
||||
return this;
|
||||
}
|
||||
getText() {
|
||||
getText(colorized = false) {
|
||||
if (this.key < 0) return '';
|
||||
var modifiers = []
|
||||
|
||||
@ -108,7 +108,18 @@ class Keybind {
|
||||
} else {
|
||||
modifiers.push(char_tl)
|
||||
}
|
||||
return modifiers.join(' + ')
|
||||
if (colorized) {
|
||||
modifiers.forEach((text, i) => {
|
||||
let type = i !== modifiers.length-1
|
||||
? text.match(/\[\w+\]/) ? 'optional' : 'modifier'
|
||||
: 'key'
|
||||
modifiers[i] = `<span class="${type}">${text}</span>`;
|
||||
})
|
||||
return modifiers.join(`<span class="punctuation"> + </span>`);
|
||||
|
||||
} else {
|
||||
return modifiers.join(' + ');
|
||||
}
|
||||
}
|
||||
getCode(key) {
|
||||
if (!key) key = this.key;
|
||||
@ -174,11 +185,11 @@ class Keybind {
|
||||
}
|
||||
isTriggered(event) {
|
||||
return (
|
||||
(this.key === event.which || (this.key == 1001 && event instanceof MouseEvent)) &&
|
||||
(this.ctrl === event.ctrlKey || this.ctrl == null ) &&
|
||||
(this.shift === event.shiftKey || this.shift == null ) &&
|
||||
(this.alt === event.altKey || this.alt == null ) &&
|
||||
(this.meta === event.metaKey || this.meta == null )
|
||||
(this.key === event.which || (this.key == 1001 && event instanceof MouseEvent)) &&
|
||||
(this.ctrl === (event.ctrlKey || Pressing.overrides.ctrl) || this.ctrl == null ) &&
|
||||
(this.shift === (event.shiftKey || Pressing.overrides.shift)|| this.shift == null ) &&
|
||||
(this.alt === (event.altKey || Pressing.overrides.alt) || this.alt == null ) &&
|
||||
(this.meta === event.metaKey || this.meta == null )
|
||||
)
|
||||
}
|
||||
record() {
|
||||
@ -282,6 +293,7 @@ Keybinds.loadKeymap = function(id, from_start_screen = false) {
|
||||
Keybinds.extra.preview_rotate.keybind.set({key: 2}).save(false);
|
||||
Keybinds.extra.preview_drag.keybind.set({key: 2, shift: true}).save(false);
|
||||
Keybinds.extra.preview_zoom.keybind.set({key: 2, ctrl: true}).save(false);
|
||||
Keybinds.extra.preview_area_select.keybind.set({key: 1}).save(false);
|
||||
}
|
||||
|
||||
Keybinds.save();
|
||||
@ -324,88 +336,17 @@ function updateKeybindConflicts() {
|
||||
})
|
||||
}
|
||||
|
||||
onVueSetup(function() {
|
||||
Keybinds.vue = new Vue({
|
||||
el: 'ul#keybindlist',
|
||||
data: {structure: Keybinds.structure},
|
||||
methods: {
|
||||
|
||||
},
|
||||
methods: {
|
||||
record(item) {
|
||||
if (!item.keybind) {
|
||||
item.keybind = new Keybind()
|
||||
}
|
||||
item.keybind.record()
|
||||
},
|
||||
reset(item) {
|
||||
if (item.keybind) {
|
||||
if (item.default_keybind) {
|
||||
item.keybind.set(item.default_keybind);
|
||||
} else {
|
||||
item.keybind.clear();
|
||||
}
|
||||
item.keybind.save(true);
|
||||
}
|
||||
},
|
||||
clear(item) {
|
||||
if (item.keybind) {
|
||||
item.keybind.clear().save(true)
|
||||
}
|
||||
},
|
||||
toggleCategory(category) {
|
||||
if (!category.open) {
|
||||
for (var ct in Keybinds.structure) {
|
||||
Keybinds.structure[ct].open = false
|
||||
}
|
||||
|
||||
}
|
||||
category.open = !category.open
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Keybinds.updateSearch = function() {
|
||||
var term = Keybinds.vue._data.search_term = $('input#keybind_search_bar').val().toLowerCase();
|
||||
var structure = Keybinds.structure;
|
||||
if (term) {
|
||||
var keywords = term.replace(/_/g, ' ').split(' ');
|
||||
|
||||
|
||||
var actions = [];
|
||||
for (var action of Keybinds.actions) {
|
||||
|
||||
if (true) {;
|
||||
var missmatch = false;
|
||||
for (var word of keywords) {
|
||||
if (
|
||||
!action.name.toLowerCase().includes(word) &&
|
||||
!action.id.toLowerCase().includes(word) &&
|
||||
!action.keybind.label.toLowerCase().includes(word)
|
||||
) {
|
||||
missmatch = true;
|
||||
}
|
||||
}
|
||||
if (!missmatch) {
|
||||
actions.push(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
structure.search_results.actions = actions
|
||||
structure.search_results.hidden = false;
|
||||
for (var key in structure) {
|
||||
structure[key].open = false
|
||||
}
|
||||
structure.search_results.open = true;
|
||||
} else {
|
||||
structure.search_results.hidden = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
BARS.defineActions(() => {
|
||||
|
||||
new Action('keybindings_window', {
|
||||
name: tl('dialog.settings.keybinds') + '...',
|
||||
icon: 'keyboard',
|
||||
category: 'blockbench',
|
||||
click: function () {
|
||||
Keybinds.dialog.show();
|
||||
}
|
||||
})
|
||||
new Action('load_keymap', {
|
||||
icon: 'format_list_bulleted',
|
||||
category: 'blockbench',
|
||||
@ -474,6 +415,138 @@ BARS.defineActions(() => {
|
||||
BarItems.export_keymap.toElement('#keybinds_title_bar')
|
||||
})
|
||||
|
||||
onVueSetup(function() {
|
||||
|
||||
let sidebar_pages = {};
|
||||
for (let key in Keybinds.structure) {
|
||||
sidebar_pages[key] = Keybinds.structure[key].name;
|
||||
}
|
||||
|
||||
Keybinds.dialog = new Dialog({
|
||||
id: 'keybindings',
|
||||
title: 'dialog.settings.keybinds',
|
||||
singleButton: true,
|
||||
width: 920,
|
||||
title_menu: new Menu([
|
||||
'settings_window',
|
||||
'keybindings_window',
|
||||
'theme_window',
|
||||
'about_window',
|
||||
]),
|
||||
sidebar: {
|
||||
pages: sidebar_pages,
|
||||
page: 'navigate',
|
||||
actions: [
|
||||
'load_keymap',
|
||||
'export_keymap',
|
||||
],
|
||||
onPageSwitch(page) {
|
||||
Keybinds.dialog.content_vue.open_category = page;
|
||||
Keybinds.dialog.content_vue.search_term = '';
|
||||
}
|
||||
},
|
||||
component: {
|
||||
data() {return {
|
||||
structure: Keybinds.structure,
|
||||
open_category: 'navigate',
|
||||
search_term: '',
|
||||
}},
|
||||
methods: {
|
||||
record(item) {
|
||||
if (!item.keybind) {
|
||||
item.keybind = new Keybind()
|
||||
}
|
||||
item.keybind.record()
|
||||
},
|
||||
reset(item) {
|
||||
if (item.keybind) {
|
||||
if (item.default_keybind) {
|
||||
item.keybind.set(item.default_keybind);
|
||||
} else {
|
||||
item.keybind.clear();
|
||||
}
|
||||
item.keybind.save(true);
|
||||
}
|
||||
},
|
||||
clear(item) {
|
||||
if (item.keybind) {
|
||||
item.keybind.clear().save(true)
|
||||
}
|
||||
},
|
||||
toggleCategory(category) {
|
||||
if (!category.open) {
|
||||
for (var ct in Keybinds.structure) {
|
||||
Keybinds.structure[ct].open = false
|
||||
}
|
||||
|
||||
}
|
||||
category.open = !category.open
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
list() {
|
||||
if (this.search_term) {
|
||||
var keywords = this.search_term.replace(/_/g, ' ').split(' ');
|
||||
var actions = [];
|
||||
|
||||
for (var action of Keybinds.actions) {
|
||||
|
||||
if (true) {;
|
||||
var missmatch = false;
|
||||
for (var word of keywords) {
|
||||
if (
|
||||
!action.name.toLowerCase().includes(word) &&
|
||||
!action.id.toLowerCase().includes(word) &&
|
||||
!action.keybind.label.toLowerCase().includes(word)
|
||||
) {
|
||||
missmatch = true;
|
||||
}
|
||||
}
|
||||
if (!missmatch) {
|
||||
actions.push(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
} else {
|
||||
return this.structure[this.open_category].actions;
|
||||
}
|
||||
},
|
||||
title() {
|
||||
if (this.search_term) {
|
||||
return tl('dialog.settings.search_results');
|
||||
} else {
|
||||
return this.structure[this.open_category].name;
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<h2 class="i_b">{{ title }}</h2>
|
||||
|
||||
<search-bar id="settings_search_bar" v-model="search_term"></search-bar>
|
||||
|
||||
<ul id="keybindlist">
|
||||
<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>
|
||||
<i class="material-icons">replay</i>
|
||||
</div>
|
||||
<div class="tool" v-on:click="clear(action)">
|
||||
<div class="tooltip">${tl('keybindings.clear')}</div>
|
||||
<i class="material-icons">clear</i>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>`
|
||||
},
|
||||
onButton() {
|
||||
Settings.save();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
window.addEventListener('blur', event => {
|
||||
if (Pressing.alt) {
|
||||
|
@ -725,9 +725,7 @@ const MenuBar = {
|
||||
{name: 'menu.help.donate', id: 'donate', icon: 'fas.fa-hand-holding-usd', click: () => {
|
||||
Blockbench.openLink('https://blockbench.net/donate/');
|
||||
}},
|
||||
{name: 'menu.help.about', id: 'about', icon: 'info', click: () => {
|
||||
Settings.open({tab: 'credits'});
|
||||
}}
|
||||
'about_window'
|
||||
])
|
||||
MenuBar.update()
|
||||
},
|
||||
|
@ -329,25 +329,6 @@ const Settings = {
|
||||
items: {}
|
||||
}
|
||||
},
|
||||
open(options = 0) {
|
||||
for (var sett in settings) {
|
||||
if (settings.hasOwnProperty(sett)) {
|
||||
Settings.old[sett] = settings[sett].value
|
||||
}
|
||||
}
|
||||
showDialog('settings')
|
||||
|
||||
setSettingsTab(options.tab || 'setting');
|
||||
|
||||
if (options.search) {
|
||||
$('dialog#settings div.search_bar input').val(options.search);
|
||||
if (options.tab == 'keybindings') {
|
||||
Keybinds.updateSearch()
|
||||
} else {
|
||||
Settings.updateSearch()
|
||||
}
|
||||
}
|
||||
},
|
||||
saveLocalStorages() {
|
||||
var settings_copy = {}
|
||||
for (var key in settings) {
|
||||
@ -402,42 +383,6 @@ const Settings = {
|
||||
}
|
||||
Blockbench.dispatchEvent('update_settings');
|
||||
},
|
||||
updateSearch() {
|
||||
var term = Settings.vue._data.search_term = $('input#settings_search_bar').val().toLowerCase();
|
||||
var structure = Settings.structure;
|
||||
if (term) {
|
||||
var keywords = term.replace(/_/g, ' ').split(' ');
|
||||
var items = {};
|
||||
for (var key in settings) {
|
||||
var setting = settings[key];
|
||||
if (Condition(setting.condition)) {
|
||||
var name = tl('settings.'+key).toLowerCase();
|
||||
var desc = tl('settings.'+key+'.desc').toLowerCase();
|
||||
var missmatch = false;
|
||||
for (var word of keywords) {
|
||||
if (
|
||||
!key.includes(word) &&
|
||||
!name.includes(word) &&
|
||||
!desc.includes(word)
|
||||
) {
|
||||
missmatch = true;
|
||||
}
|
||||
}
|
||||
if (!missmatch) {
|
||||
items[key] = setting;
|
||||
}
|
||||
}
|
||||
}
|
||||
structure.search_results.items = items
|
||||
structure.search_results.hidden = false;
|
||||
for (var key in structure) {
|
||||
structure[key].open = false
|
||||
}
|
||||
structure.search_results.open = true;
|
||||
} else {
|
||||
structure.search_results.hidden = true;
|
||||
}
|
||||
},
|
||||
import(file) {
|
||||
let data = JSON.parse(file.content);
|
||||
for (let key in settings) {
|
||||
@ -474,6 +419,18 @@ function updateStreamerModeNotification() {
|
||||
}
|
||||
|
||||
BARS.defineActions(() => {
|
||||
new Action('settings_window', {
|
||||
icon: 'settings',
|
||||
category: 'blockbench',
|
||||
click: function () {
|
||||
for (var sett in settings) {
|
||||
if (settings.hasOwnProperty(sett)) {
|
||||
Settings.old[sett] = settings[sett].value
|
||||
}
|
||||
}
|
||||
Settings.dialog.show()
|
||||
}
|
||||
})
|
||||
|
||||
new Action('import_settings', {
|
||||
icon: 'folder',
|
||||
@ -530,12 +487,6 @@ BARS.defineActions(() => {
|
||||
})
|
||||
|
||||
onVueSetup(function() {
|
||||
Settings.structure.search_results = {
|
||||
name: tl('dialog.settings.search_results'),
|
||||
hidden: true,
|
||||
open: true,
|
||||
items: {}
|
||||
}
|
||||
for (var key in settings) {
|
||||
var category = settings[key].category
|
||||
if (!category) category = 'general'
|
||||
@ -549,24 +500,133 @@ onVueSetup(function() {
|
||||
}
|
||||
Settings.structure[category].items[key] = settings[key]
|
||||
}
|
||||
Settings.vue = new Vue({
|
||||
el: 'ul#settingslist',
|
||||
data: {
|
||||
structure: Settings.structure,
|
||||
search_term: ''
|
||||
|
||||
let sidebar_pages = {};
|
||||
for (let key in Settings.structure) {
|
||||
sidebar_pages[key] = Settings.structure[key].name;
|
||||
}
|
||||
|
||||
Settings.dialog = new Dialog({
|
||||
id: 'settings',
|
||||
title: 'dialog.settings.settings',
|
||||
width: 920,
|
||||
singleButton: true,
|
||||
title_menu: new Menu([
|
||||
'settings_window',
|
||||
'keybindings_window',
|
||||
'theme_window',
|
||||
'about_window',
|
||||
]),
|
||||
sidebar: {
|
||||
pages: sidebar_pages,
|
||||
page: 'general',
|
||||
actions: [
|
||||
'import_settings',
|
||||
'export_settings',
|
||||
],
|
||||
onPageSwitch(page) {
|
||||
Settings.dialog.content_vue.open_category = page;
|
||||
Settings.dialog.content_vue.search_term = '';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveSettings() {
|
||||
Settings.saveLocalStorages();
|
||||
component: {
|
||||
data() {return {
|
||||
structure: Settings.structure,
|
||||
open_category: 'general',
|
||||
search_term: '',
|
||||
}},
|
||||
methods: {
|
||||
saveSettings() {
|
||||
Settings.saveLocalStorages();
|
||||
}
|
||||
},
|
||||
toggleCategory(category) {
|
||||
if (!category.open) {
|
||||
for (var ct in Settings.structure) {
|
||||
Settings.structure[ct].open = false
|
||||
computed: {
|
||||
list() {
|
||||
if (this.search_term) {
|
||||
var keywords = this.search_term.replace(/_/g, ' ').split(' ');
|
||||
var items = {};
|
||||
for (var key in settings) {
|
||||
var setting = settings[key];
|
||||
if (Condition(setting.condition)) {
|
||||
var name = setting.name.toLowerCase();
|
||||
var desc = setting.description.toLowerCase();
|
||||
var missmatch = false;
|
||||
for (var word of keywords) {
|
||||
if (
|
||||
!key.includes(word) &&
|
||||
!name.includes(word) &&
|
||||
!desc.includes(word)
|
||||
) {
|
||||
missmatch = true;
|
||||
}
|
||||
}
|
||||
if (!missmatch) {
|
||||
items[key] = setting;
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
} else {
|
||||
return this.structure[this.open_category].items;
|
||||
}
|
||||
},
|
||||
title() {
|
||||
if (this.search_term) {
|
||||
return tl('dialog.settings.search_results');
|
||||
} else {
|
||||
return this.structure[this.open_category].name;
|
||||
}
|
||||
}
|
||||
category.open = !category.open
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<h2 class="i_b">{{ title }}</h2>
|
||||
|
||||
<search-bar id="settings_search_bar" v-model="search_term"></search-bar>
|
||||
|
||||
<ul id="settingslist">
|
||||
|
||||
<li v-for="(setting, key) in list" v-if="Condition(setting.condition)" v-on="setting.click ? {click: setting.click} : {}">
|
||||
<template v-if="setting.type === 'number'">
|
||||
<div class="setting_element"><input type="number" v-model.number="setting.value" :min="setting.min" :max="setting.max" :step="setting.step" v-on:input="saveSettings()"></div>
|
||||
</template>
|
||||
<template v-else-if="setting.type === 'click'">
|
||||
<div class="setting_element setting_icon" v-html="Blockbench.getIconNode(setting.icon).outerHTML"></div>
|
||||
</template>
|
||||
<template v-else-if="setting.type == 'toggle'"><!--TOGGLE-->
|
||||
<div class="setting_element"><input type="checkbox" v-model="setting.value" v-bind:id="'setting_'+key" v-on:click="saveSettings()"></div>
|
||||
</template>
|
||||
|
||||
<label class="setting_label" v-bind:for="'setting_'+key">
|
||||
<div class="setting_name">{{ setting.name }}</div>
|
||||
<div class="setting_description">{{ setting.description }}</div>
|
||||
</label>
|
||||
|
||||
<template v-if="setting.type === 'text'">
|
||||
<input type="text" class="dark_bordered" style="width: 96%" v-model="setting.value" v-on:input="saveSettings()">
|
||||
</template>
|
||||
|
||||
<template v-if="setting.type === 'password'">
|
||||
<input :type="setting.hidden ? 'password' : 'text'" class="dark_bordered" style="width: calc(96% - 28px);" v-model="setting.value" v-on:input="saveSettings()">
|
||||
<div class="password_toggle" @click="setting.hidden = !setting.hidden;">
|
||||
<i class="fas fa-eye-slash" v-if="setting.hidden"></i>
|
||||
<i class="fas fa-eye" v-else></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="setting.type === 'select'">
|
||||
<div class="bar_select">
|
||||
<select v-model="setting.value">
|
||||
<option v-for="(text, id) in setting.options" v-bind:value="id">{{ text }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
</div>`
|
||||
},
|
||||
onButton() {
|
||||
Settings.save();
|
||||
}
|
||||
})
|
||||
})
|
@ -4,7 +4,7 @@ const CustomTheme = {
|
||||
headline_font: '',
|
||||
code_font: '',
|
||||
css: '',
|
||||
colors: {}
|
||||
colors: {},
|
||||
},
|
||||
defaultColors: {
|
||||
ui: '#282c34',
|
||||
@ -34,65 +34,153 @@ const CustomTheme = {
|
||||
localStorage.setItem('theme', JSON.stringify(CustomTheme.data));
|
||||
}
|
||||
|
||||
CustomTheme.vue = new Vue({
|
||||
el: '#theme_editor',
|
||||
data: CustomTheme.data,
|
||||
components: {
|
||||
VuePrismEditor
|
||||
CustomTheme.dialog = new Dialog({
|
||||
id: 'theme',
|
||||
title: 'dialog.settings.theme',
|
||||
singleButton: true,
|
||||
width: 920,
|
||||
title_menu: new Menu([
|
||||
'settings_window',
|
||||
'keybindings_window',
|
||||
'theme_window',
|
||||
'about_window',
|
||||
]),
|
||||
sidebar: {
|
||||
pages: {
|
||||
//discover: tl('layout.discover'),
|
||||
color: tl('layout.color'),
|
||||
fonts: tl('layout.fonts'),
|
||||
css: tl('layout.css'),
|
||||
},
|
||||
page: 'color',
|
||||
actions: [
|
||||
{
|
||||
name: 'layout.documentation',
|
||||
icon: 'fa-book',
|
||||
click() {
|
||||
|
||||
}
|
||||
},
|
||||
'import_theme',
|
||||
'export_theme',
|
||||
],
|
||||
onPageSwitch(page) {
|
||||
CustomTheme.dialog.content_vue.open_category = page;
|
||||
if (page == 'color' && !CustomTheme.dialog_is_setup) {
|
||||
CustomTheme.setupDialog()
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
main_font() {
|
||||
document.body.style.setProperty('--font-custom-main', CustomTheme.data.main_font);
|
||||
saveChanges();
|
||||
component: {
|
||||
data: {
|
||||
data: CustomTheme.data,
|
||||
open_category: 'color'
|
||||
},
|
||||
headline_font() {
|
||||
document.body.style.setProperty('--font-custom-headline', CustomTheme.data.headline_font);
|
||||
saveChanges();
|
||||
components: {
|
||||
VuePrismEditor
|
||||
},
|
||||
code_font() {
|
||||
document.body.style.setProperty('--font-custom-code', CustomTheme.data.code_font);
|
||||
saveChanges();
|
||||
},
|
||||
css() {
|
||||
$('style#theme_css').text(CustomTheme.data.css);
|
||||
saveChanges();
|
||||
},
|
||||
colors: {
|
||||
handler() {
|
||||
for (var key in CustomTheme.data.colors) {
|
||||
var hex = CustomTheme.data.colors[key];
|
||||
document.body.style.setProperty('--color-'+key, hex);
|
||||
}
|
||||
$('meta[name=theme-color]').attr('content', CustomTheme.data.colors.frame);
|
||||
|
||||
var c_outline = parseInt('0x'+CustomTheme.data.colors.accent.replace('#', ''))
|
||||
if (c_outline !== gizmo_colors.outline.getHex()) {
|
||||
gizmo_colors.outline.set(c_outline)
|
||||
Canvas.outlineMaterial.color = gizmo_colors.outline
|
||||
}
|
||||
var c_wire = parseInt('0x'+CustomTheme.data.colors.wireframe.replace('#', ''))
|
||||
if (c_wire !== gizmo_colors.wire.getHex()) {
|
||||
gizmo_colors.wire.set(c_wire);
|
||||
Canvas.wireframeMaterial.color = gizmo_colors.wire;
|
||||
}
|
||||
|
||||
var c_grid = parseInt('0x'+CustomTheme.data.colors.grid.replace('#', ''))
|
||||
if (c_grid !== gizmo_colors.grid.getHex()) {
|
||||
gizmo_colors.grid.set(c_grid);
|
||||
three_grid.children.forEach(c => {
|
||||
if (c.name === 'grid' && c.material) {
|
||||
c.material.color = gizmo_colors.grid;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch: {
|
||||
'data.main_font'() {
|
||||
document.body.style.setProperty('--font-custom-main', CustomTheme.data.main_font);
|
||||
saveChanges();
|
||||
},
|
||||
deep: true
|
||||
'data.headline_font'() {
|
||||
document.body.style.setProperty('--font-custom-headline', CustomTheme.data.headline_font);
|
||||
saveChanges();
|
||||
},
|
||||
'data.code_font'() {
|
||||
document.body.style.setProperty('--font-custom-code', CustomTheme.data.code_font);
|
||||
saveChanges();
|
||||
},
|
||||
'data.css'() {
|
||||
$('style#theme_css').text(CustomTheme.data.css);
|
||||
saveChanges();
|
||||
},
|
||||
'data.colors': {
|
||||
handler() {
|
||||
for (var key in CustomTheme.data.colors) {
|
||||
var hex = CustomTheme.data.colors[key];
|
||||
document.body.style.setProperty('--color-'+key, hex);
|
||||
}
|
||||
$('meta[name=theme-color]').attr('content', CustomTheme.data.colors.frame);
|
||||
|
||||
var c_outline = parseInt('0x'+CustomTheme.data.colors.accent.replace('#', ''))
|
||||
if (c_outline !== gizmo_colors.outline.getHex()) {
|
||||
gizmo_colors.outline.set(c_outline)
|
||||
Canvas.outlineMaterial.color = gizmo_colors.outline
|
||||
}
|
||||
var c_wire = parseInt('0x'+CustomTheme.data.colors.wireframe.replace('#', ''))
|
||||
if (c_wire !== gizmo_colors.wire.getHex()) {
|
||||
gizmo_colors.wire.set(c_wire);
|
||||
Canvas.wireframeMaterial.color = gizmo_colors.wire;
|
||||
}
|
||||
|
||||
var c_grid = parseInt('0x'+CustomTheme.data.colors.grid.replace('#', ''))
|
||||
if (c_grid !== gizmo_colors.grid.getHex()) {
|
||||
gizmo_colors.grid.set(c_grid);
|
||||
three_grid.children.forEach(c => {
|
||||
if (c.name === 'grid' && c.material) {
|
||||
c.material.color = gizmo_colors.grid;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
saveChanges();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
template: `
|
||||
<div id="theme_editor">
|
||||
<div v-if="open_category == 'discover'">
|
||||
<h2 class="i_b">${tl('layout.discover')}</h2>
|
||||
</div>
|
||||
<div v-show="open_category == 'color'">
|
||||
<h2 class="i_b">${tl('layout.color')}</h2>
|
||||
<div id="color_wrapper">
|
||||
<div class="color_field" v-for="(color, key) in data.colors" :id="'color_field_' + key">
|
||||
<div class="layout_color_preview color_input" :style="{'background-color': color}"></div>
|
||||
<div class="desc">
|
||||
<h4>{{ tl('layout.color.'+key) }}</h4>
|
||||
<p>{{ tl('layout.color.'+key+'.desc') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="open_category == 'fonts'">
|
||||
<h2 class="i_b">${tl('layout.fonts')}</h2>
|
||||
<div class="dialog_bar">
|
||||
<label class="name_space_left" for="layout_font_main">${tl('layout.font.main')}</label>
|
||||
<input style="font-family: var(--font-main)" type="text" class="half dark_bordered" id="layout_font_main" v-model="data.main_font">
|
||||
</div>
|
||||
|
||||
<div class="dialog_bar">
|
||||
<label class="name_space_left" for="layout_font_headline">${tl('layout.font.headline')}</label>
|
||||
<input style="font-family: var(--font-headline)" type="text" class="half dark_bordered" id="layout_font_headline" v-model="data.headline_font">
|
||||
</div>
|
||||
<div class="dialog_bar">
|
||||
<label class="name_space_left" for="layout_font_cpde">${tl('layout.font.code')}</label>
|
||||
<input style="font-family: var(--font-code)" type="text" class="half dark_bordered" id="layout_font_cpde" v-model="data.code_font">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="open_category == 'css'">
|
||||
<h2 class="i_b">${tl('layout.css')}</h2>
|
||||
<div id="css_editor">
|
||||
<vue-prism-editor v-model="data.css" language="css" :line-numbers="true" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>`
|
||||
},
|
||||
onButton() {
|
||||
Settings.save();
|
||||
}
|
||||
})
|
||||
|
||||
Vue.nextTick(function() {
|
||||
CustomTheme.fetchFromStorage();
|
||||
})
|
||||
@ -214,6 +302,14 @@ const CustomTheme = {
|
||||
|
||||
|
||||
BARS.defineActions(function() {
|
||||
new Action('theme_window', {
|
||||
name: tl('dialog.settings.theme') + '...',
|
||||
icon: 'style',
|
||||
category: 'blockbench',
|
||||
click: function () {
|
||||
CustomTheme.dialog.show();
|
||||
}
|
||||
})
|
||||
new Action('import_theme', {
|
||||
icon: 'folder',
|
||||
category: 'blockbench',
|
||||
@ -271,4 +367,7 @@ BARS.defineActions(function() {
|
||||
BarItems.import_theme.toElement('#layout_title_bar')
|
||||
BarItems.export_theme.toElement('#layout_title_bar')
|
||||
BarItems.reset_theme.toElement('#layout_title_bar')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
@ -501,6 +501,8 @@ BARS.defineActions(function() {
|
||||
Codecs.project.write(Codecs.project.compile(), Project.save_path);
|
||||
} else if (Format.codec && Format.codec.export) {
|
||||
Format.codec.export()
|
||||
} else {
|
||||
Project.saved = true;
|
||||
}
|
||||
}
|
||||
if (Format.animation_mode && Format.animation_files && Animation.all.length) {
|
||||
|
@ -74,7 +74,7 @@ class Group extends OutlinerNode {
|
||||
|
||||
//Clear Old Group
|
||||
if (Group.selected) Group.selected.unselect()
|
||||
if (event.shiftKey !== true && event.ctrlOrCmd !== true) {
|
||||
if ((event.shiftKey || Pressing.overrides.shift) !== true && (event.ctrlOrCmd || Pressing.overrides.ctrl) !== true) {
|
||||
selected.length = 0
|
||||
}
|
||||
//Select This Group
|
||||
|
@ -410,7 +410,7 @@ class OutlinerElement extends OutlinerNode {
|
||||
if (Modes.animate && this.constructor != NullObject) return false;
|
||||
//Shiftv
|
||||
var just_selected = []
|
||||
if (event && event.shiftKey === true && this.getParentArray().includes(selected[selected.length-1]) && !Modes.paint && isOutlinerClick) {
|
||||
if (event && (event.shiftKey === true || Pressing.overrides.shift) && this.getParentArray().includes(selected[selected.length-1]) && !Modes.paint && isOutlinerClick) {
|
||||
var starting_point;
|
||||
var last_selected = selected[selected.length-1]
|
||||
this.getParentArray().forEach((s, i) => {
|
||||
@ -441,7 +441,7 @@ class OutlinerElement extends OutlinerNode {
|
||||
})
|
||||
|
||||
//Control
|
||||
} else if (event && !Modes.paint && (event.ctrlOrCmd || event.shiftKey )) {
|
||||
} else if (event && !Modes.paint && (event.ctrlOrCmd || event.shiftKey || Pressing.overrides.ctrl || Pressing.overrides.shift)) {
|
||||
if (selected.includes(this)) {
|
||||
selected.replace(selected.filter((e) => {
|
||||
return e !== this
|
||||
@ -742,7 +742,7 @@ function dropOutlinerObjects(item, target, event, order) {
|
||||
} else {
|
||||
var items = [item];
|
||||
}
|
||||
if (event.altKey) {
|
||||
if (event.altKey || Pressing.overrides.alt) {
|
||||
Undo.initEdit({elements: [], outliner: true, selection: true})
|
||||
Outliner.selected.empty();
|
||||
} else {
|
||||
@ -776,7 +776,7 @@ function dropOutlinerObjects(item, target, event, order) {
|
||||
}
|
||||
items.forEach(function(item) {
|
||||
if (item && item !== target) {
|
||||
if (event.altKey) {
|
||||
if (event.altKey || Pressing.overrides.alt) {
|
||||
if (item instanceof Group) {
|
||||
var dupl = item.duplicate()
|
||||
place(dupl)
|
||||
@ -797,7 +797,7 @@ function dropOutlinerObjects(item, target, event, order) {
|
||||
if (Format.bone_rig) {
|
||||
Canvas.updateAllBones()
|
||||
}
|
||||
if (event.altKey) {
|
||||
if (event.altKey || Pressing.overrides.alt) {
|
||||
updateSelection()
|
||||
Undo.finishEdit('Duplicate selection', {elements: selected, outliner: true, selection: true})
|
||||
} else {
|
||||
@ -1242,7 +1242,7 @@ Interface.definePanels(function() {
|
||||
convertTouchEvent(e2);
|
||||
if (e2.target.classList.contains('outliner_toggle') && e2.target.getAttribute('toggle') == key) {
|
||||
let [node] = eventTargetToNode(e2.target);
|
||||
if (key == 'visibility' && e2.altKey && !affected.length) {
|
||||
if (key == 'visibility' && (e2.altKey || Pressing.overrides.alt) && !affected.length) {
|
||||
let new_affected = Outliner.elements.filter(node => !node.selected);
|
||||
value = !(new_affected[0] && new_affected[0][key]);
|
||||
new_affected.forEach(node => {
|
||||
|
@ -280,7 +280,8 @@ class Preview {
|
||||
this.loadBackground()
|
||||
|
||||
this.selection = {
|
||||
box: $('<div id="selection_box" class="selection_rectangle"></div>')
|
||||
box: $('<div id="selection_box" class="selection_rectangle"></div>'),
|
||||
frustum: new THREE.Frustum()
|
||||
}
|
||||
|
||||
this.raycaster = new THREE.Raycaster();
|
||||
@ -682,7 +683,7 @@ class Preview {
|
||||
}
|
||||
if (data.element.parent.type === 'group' && (
|
||||
Animator.open ||
|
||||
event.shiftKey ||
|
||||
event.shiftKey || Pressing.overrides.shift ||
|
||||
(!Format.rotate_cubes && Format.bone_rig && ['rotate_tool', 'pivot_tool'].includes(Toolbox.selected.id))
|
||||
)) {
|
||||
data.element.parent.select().showInOutliner();
|
||||
@ -706,7 +707,7 @@ class Preview {
|
||||
Toolbox.selected.onCanvasClick({event})
|
||||
}
|
||||
|
||||
if (this.angle !== null && this.camOrtho.axis || this.movingBackground) {
|
||||
if ((Keybinds.extra.preview_area_select.keybind.isTriggered(event)) || this.movingBackground) {
|
||||
this.startSelRect(event)
|
||||
} else {
|
||||
return false;
|
||||
@ -806,18 +807,13 @@ class Preview {
|
||||
this.selection.activated = settings.canvas_unselect.value;
|
||||
this.selection.old_selected = selected.slice();
|
||||
|
||||
var ray = this.raycastMouseCoords(event.clientX, event.clientY)
|
||||
|
||||
this.selection.start_u = ray[this.getUVAxes().u]
|
||||
this.selection.start_v = ray[this.getUVAxes().v]
|
||||
|
||||
this.moveSelRect(event)
|
||||
}
|
||||
moveSelRect(event) {
|
||||
var scope = this;
|
||||
|
||||
if (this.movingBackground) {
|
||||
if (event.shiftKey) {
|
||||
if (event.shiftKey || Pressing.overrides.shift) {
|
||||
this.background.size = limitNumber( this.background.before.size + (event.offsetY - this.selection.start_y), 0, 10e3)
|
||||
} else {
|
||||
this.background.x = this.background.before.x + (event.offsetX - this.selection.start_x);
|
||||
@ -827,7 +823,6 @@ class Preview {
|
||||
return;
|
||||
}
|
||||
|
||||
var uv_axes = this.getUVAxes()
|
||||
//Overlay
|
||||
var c = getRectangle(
|
||||
Math.clamp(this.selection.start_x, -2, this.width),
|
||||
@ -848,45 +843,159 @@ class Preview {
|
||||
//Select
|
||||
if (!this.selection.activated) return;
|
||||
|
||||
var ray = this.raycastMouseCoords(event.clientX, event.clientY)
|
||||
/**
|
||||
* Contains code from https://github.com/mrdoob/three.js/blob/dev/examples/jsm/interactive/SelectionBox.js
|
||||
* MIT, by three.js contributors
|
||||
*/
|
||||
|
||||
var canvas_offset = $(this.canvas).offset()
|
||||
let startPoint = new THREE.Vector3(
|
||||
( (this.selection.client_x - canvas_offset.left) / this.width ) * 2 - 1,
|
||||
- ( (this.selection.client_y - canvas_offset.top) / this.height ) * 2 + 1,
|
||||
0.5
|
||||
);
|
||||
let endPoint = new THREE.Vector3(
|
||||
(( event.clientX - canvas_offset.left) / this.width ) * 2 - 1,
|
||||
- (( event.clientY - canvas_offset.top) / this.height ) * 2 + 1,
|
||||
0.5
|
||||
);
|
||||
|
||||
if (startPoint.x === endPoint.x) {
|
||||
endPoint.x += 0.1;
|
||||
} else if (startPoint.x < endPoint.x) {
|
||||
[startPoint.x, endPoint.x] = [endPoint.x, startPoint.x];
|
||||
}
|
||||
|
||||
if (startPoint.y === endPoint.y) {
|
||||
endPoint.y += 0.1;
|
||||
} else if (startPoint.y > endPoint.y) {
|
||||
[startPoint.y, endPoint.y] = [endPoint.y, startPoint.y];
|
||||
}
|
||||
|
||||
this.camera.updateProjectionMatrix();
|
||||
this.camera.updateMatrixWorld();
|
||||
|
||||
const _tmpPoint = new THREE.Vector3();
|
||||
|
||||
const _vecNear = new THREE.Vector3();
|
||||
const _vecTopLeft = new THREE.Vector3();
|
||||
const _vecTopRight = new THREE.Vector3();
|
||||
const _vecDownRight = new THREE.Vector3();
|
||||
const _vecDownLeft = new THREE.Vector3();
|
||||
|
||||
const _vecFarTopLeft = new THREE.Vector3();
|
||||
const _vecFarTopRight = new THREE.Vector3();
|
||||
const _vecFarDownRight = new THREE.Vector3();
|
||||
const _vecFarDownLeft = new THREE.Vector3();
|
||||
|
||||
const _vectemp1 = new THREE.Vector3();
|
||||
const _vectemp2 = new THREE.Vector3();
|
||||
const _vectemp3 = new THREE.Vector3();
|
||||
|
||||
if ( !this.isOrtho ) {
|
||||
|
||||
_tmpPoint.copy( startPoint );
|
||||
_tmpPoint.x = Math.min( startPoint.x, endPoint.x );
|
||||
_tmpPoint.y = Math.max( startPoint.y, endPoint.y );
|
||||
endPoint.x = Math.max( startPoint.x, endPoint.x );
|
||||
endPoint.y = Math.min( startPoint.y, endPoint.y );
|
||||
|
||||
_vecNear.setFromMatrixPosition( this.camera.matrixWorld );
|
||||
_vecTopLeft.copy( _tmpPoint );
|
||||
_vecTopRight.set( endPoint.x, _tmpPoint.y, 0 );
|
||||
_vecDownRight.copy( endPoint );
|
||||
_vecDownLeft.set( _tmpPoint.x, endPoint.y, 0 );
|
||||
|
||||
_vecTopLeft.unproject( this.camera );
|
||||
_vecTopRight.unproject( this.camera );
|
||||
_vecDownRight.unproject( this.camera );
|
||||
_vecDownLeft.unproject( this.camera );
|
||||
|
||||
_vectemp1.copy( _vecTopLeft ).sub( _vecNear );
|
||||
_vectemp2.copy( _vecTopRight ).sub( _vecNear );
|
||||
_vectemp3.copy( _vecDownRight ).sub( _vecNear );
|
||||
_vectemp1.normalize();
|
||||
_vectemp2.normalize();
|
||||
_vectemp3.normalize();
|
||||
|
||||
_vectemp1.multiplyScalar( this.deep );
|
||||
_vectemp2.multiplyScalar( this.deep );
|
||||
_vectemp3.multiplyScalar( this.deep );
|
||||
_vectemp1.add( _vecNear );
|
||||
_vectemp2.add( _vecNear );
|
||||
_vectemp3.add( _vecNear );
|
||||
|
||||
const planes = this.selection.frustum.planes;
|
||||
|
||||
planes[ 0 ].setFromCoplanarPoints( _vecNear, _vecTopLeft, _vecTopRight );
|
||||
planes[ 1 ].setFromCoplanarPoints( _vecNear, _vecTopRight, _vecDownRight );
|
||||
planes[ 2 ].setFromCoplanarPoints( _vecDownRight, _vecDownLeft, _vecNear );
|
||||
planes[ 3 ].setFromCoplanarPoints( _vecDownLeft, _vecTopLeft, _vecNear );
|
||||
planes[ 4 ].setFromCoplanarPoints( _vecTopRight, _vecDownRight, _vecDownLeft );
|
||||
planes[ 5 ].setFromCoplanarPoints( _vectemp3, _vectemp2, _vectemp1 );
|
||||
planes[ 5 ].normal.multiplyScalar( - 1 );
|
||||
|
||||
} else {
|
||||
|
||||
const left = Math.min( startPoint.x, endPoint.x );
|
||||
const top = Math.max( startPoint.y, endPoint.y );
|
||||
const right = Math.max( startPoint.x, endPoint.x );
|
||||
const down = Math.min( startPoint.y, endPoint.y );
|
||||
|
||||
_vecTopLeft.set( left, top, - 1 );
|
||||
_vecTopRight.set( right, top, - 1 );
|
||||
_vecDownRight.set( right, down, - 1 );
|
||||
_vecDownLeft.set( left, down, - 1 );
|
||||
|
||||
_vecFarTopLeft.set( left, top, 1 );
|
||||
_vecFarTopRight.set( right, top, 1 );
|
||||
_vecFarDownRight.set( right, down, 1 );
|
||||
_vecFarDownLeft.set( left, down, 1 );
|
||||
|
||||
_vecTopLeft.unproject( this.camera );
|
||||
_vecTopRight.unproject( this.camera );
|
||||
_vecDownRight.unproject( this.camera );
|
||||
_vecDownLeft.unproject( this.camera );
|
||||
|
||||
_vecFarTopLeft.unproject( this.camera );
|
||||
_vecFarTopRight.unproject( this.camera );
|
||||
_vecFarDownRight.unproject( this.camera );
|
||||
_vecFarDownLeft.unproject( this.camera );
|
||||
|
||||
const planes = this.selection.frustum.planes;
|
||||
|
||||
planes[ 0 ].setFromCoplanarPoints( _vecTopLeft, _vecFarTopLeft, _vecFarTopRight );
|
||||
planes[ 1 ].setFromCoplanarPoints( _vecTopRight, _vecFarTopRight, _vecFarDownRight );
|
||||
planes[ 2 ].setFromCoplanarPoints( _vecFarDownRight, _vecFarDownLeft, _vecDownLeft );
|
||||
planes[ 3 ].setFromCoplanarPoints( _vecFarDownLeft, _vecFarTopLeft, _vecTopLeft );
|
||||
planes[ 4 ].setFromCoplanarPoints( _vecTopRight, _vecDownRight, _vecDownLeft );
|
||||
planes[ 5 ].setFromCoplanarPoints( _vecFarDownRight, _vecFarTopRight, _vecFarTopLeft );
|
||||
planes[ 5 ].normal.multiplyScalar( - 1 );
|
||||
|
||||
}
|
||||
|
||||
let box = new THREE.Box3();
|
||||
let vector = new THREE.Vector3();
|
||||
|
||||
var plane_rect = getRectangle(
|
||||
this.selection.start_u,
|
||||
this.selection.start_v,
|
||||
ray[uv_axes.u],
|
||||
ray[uv_axes.v]
|
||||
)
|
||||
unselectAll()
|
||||
Outliner.elements.forEach(function(cube) {
|
||||
Outliner.elements.forEach((element) => {
|
||||
let isSelected;
|
||||
if ((event.shiftKey || event.ctrlOrCmd || Pressing.overrides.ctrl || Pressing.overrides.shift) && scope.selection.old_selected.indexOf(element) >= 0) {
|
||||
isSelected = true
|
||||
|
||||
if ((event.shiftKey || event.ctrlOrCmd) && scope.selection.old_selected.indexOf(cube) >= 0) {
|
||||
var isSelected = true
|
||||
} else {
|
||||
if (cube instanceof Cube && cube.visibility && cube.mesh) {
|
||||
var mesh = cube.mesh
|
||||
var from = new THREE.Vector3().copy(mesh.geometry.vertices[6]).applyMatrix4(mesh.matrixWorld)
|
||||
var to = new THREE.Vector3().copy(mesh.geometry.vertices[0]).applyMatrix4(mesh.matrixWorld)
|
||||
var cube_rect = getRectangle(
|
||||
from[uv_axes.u],
|
||||
from[uv_axes.v],
|
||||
to[uv_axes.u],
|
||||
to[uv_axes.v]
|
||||
)
|
||||
var isSelected = doRectanglesOverlap(plane_rect, cube_rect)
|
||||
} else if (cube instanceof Locator && cube.parent instanceof Group && cube.parent.mesh) {
|
||||
var mesh = cube.parent.mesh;
|
||||
var pos = new THREE.Vector3().fromArray(cube.from).applyMatrix4(mesh.matrixWorld);
|
||||
var cube_rect = getRectangle(
|
||||
pos[uv_axes.u],
|
||||
pos[uv_axes.v],
|
||||
pos[uv_axes.u],
|
||||
pos[uv_axes.v]
|
||||
)
|
||||
var isSelected = doRectanglesOverlap(plane_rect, cube_rect)
|
||||
} else if (element.visibility) {
|
||||
if (element.mesh && element.mesh.geometry) {
|
||||
box.copy(element.mesh.geometry.boundingBox).applyMatrix4(element.mesh.matrixWorld);
|
||||
isSelected = this.selection.frustum.intersectsBox(box);
|
||||
|
||||
} else if (element.mesh) {
|
||||
|
||||
element.mesh.getWorldPosition(vector);
|
||||
isSelected = this.selection.frustum.containsPoint(vector);
|
||||
}
|
||||
}
|
||||
if (isSelected) {
|
||||
cube.selectLow()
|
||||
element.selectLow()
|
||||
}
|
||||
})
|
||||
TickUpdates.selection = true;
|
||||
@ -901,13 +1010,6 @@ class Preview {
|
||||
this.selection.box.detach()
|
||||
this.selection.activated = false;
|
||||
}
|
||||
getUVAxes() {
|
||||
switch (this.camOrtho.axis) {
|
||||
case 'x': return {u: 'z', v: 'y'}; break;
|
||||
case 'y': return {u: 'x', v: 'z'}; break;
|
||||
case 'z': return {u: 'x', v: 'y'}; break;
|
||||
}
|
||||
}
|
||||
|
||||
//Backgrounds
|
||||
getBackground() {
|
||||
|
@ -26,7 +26,10 @@
|
||||
|
||||
if ( highlighted ) {
|
||||
|
||||
this.color.setHex( parseInt(CustomTheme.data.colors.accent.replace('#', ''), 16) );
|
||||
this.color.copy( gizmo_colors.outline );
|
||||
this.color.r *= 1.2;
|
||||
this.color.g *= 1.2;
|
||||
this.color.b *= 1.2;
|
||||
this.opacity = 1;
|
||||
|
||||
} else {
|
||||
@ -58,7 +61,10 @@
|
||||
|
||||
if ( highlighted ) {
|
||||
|
||||
this.color.setHex( parseInt(CustomTheme.data.colors.accent.replace('#', ''), 16) );
|
||||
this.color.copy( gizmo_colors.outline );
|
||||
this.color.r *= 1.2;
|
||||
this.color.g *= 1.2;
|
||||
this.color.b *= 1.2;
|
||||
this.opacity = 1;
|
||||
|
||||
} else {
|
||||
@ -179,8 +185,7 @@
|
||||
|
||||
if ( child.material && child.material.highlight ) {
|
||||
|
||||
|
||||
if ( child.name === axis && axis_letter && child.scale[axis_letter] < 5) {
|
||||
if ( child.name === axis && axis_letter && (child.scale[axis_letter] < 5 || axis == 'E') ) {
|
||||
|
||||
child.material.highlight( true );
|
||||
|
||||
@ -415,7 +420,11 @@
|
||||
[ new THREE.Line( new CircleGeometry( 1, 'z', 0.5 ), new GizmoLineMaterial( { color: gizmo_colors.b } ) ) ],
|
||||
[ new THREE.Mesh( new THREE.OctahedronBufferGeometry( 0.06, 0 ), new GizmoLineMaterial( { color: gizmo_colors.b } ) ), [ 0.98, 0, 0 ], null, [ 1, 4, 1 ] ],
|
||||
],
|
||||
XYZE: [[ new THREE.Line( new CircleGeometry( 1, 'z', 1 ), new GizmoLineMaterial( { color: 0x787878 } ) ) ]]
|
||||
|
||||
E: [
|
||||
[ new THREE.Line( new CircleGeometry( 1.2, 'z', 1 ), new GizmoLineMaterial( { color: gizmo_colors.outline } ) ) ]
|
||||
],
|
||||
XYZE: [[ new THREE.Line( new CircleGeometry( 1, 'z', 1 ), new GizmoLineMaterial( { color: gizmo_colors.grid } ) ) ]]
|
||||
|
||||
};
|
||||
|
||||
@ -423,7 +432,8 @@
|
||||
|
||||
X: [[ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, - Math.PI / 2, - Math.PI / 2 ] ]],
|
||||
Y: [[ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ Math.PI / 2, 0, 0 ] ]],
|
||||
Z: [[ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ]]
|
||||
Z: [[ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.12, 4, 12, Math.PI ), pickerMaterial ), [ 0, 0, 0 ], [ 0, 0, - Math.PI / 2 ] ]],
|
||||
E: [[ new THREE.Mesh( new THREE.TorusBufferGeometry( 1.2, 0.12, 2, 24 ), pickerMaterial ) ]],
|
||||
|
||||
};
|
||||
|
||||
@ -443,13 +453,6 @@
|
||||
|
||||
THREE.TransformGizmo.prototype.update.apply( this, arguments );
|
||||
|
||||
var group = {
|
||||
|
||||
handles: this[ "handles" ],
|
||||
pickers: this[ "pickers" ],
|
||||
|
||||
};
|
||||
|
||||
var tempMatrix = new THREE.Matrix4();
|
||||
var worldRotation = new THREE.Euler( 0, 0, 1 );
|
||||
var tempQuaternion = new THREE.Quaternion();
|
||||
@ -1130,6 +1133,7 @@
|
||||
|
||||
var axis = scope.axis.substr(-1).toLowerCase()
|
||||
var axisNumber = getAxisNumber(axis)
|
||||
var rotate_normal;
|
||||
|
||||
point.copy( planeIntersect.point );
|
||||
|
||||
@ -1140,14 +1144,24 @@
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
point.sub( worldPosition );
|
||||
point.removeEuler(worldRotation)
|
||||
var rotations = [
|
||||
Math.atan2( point.z, point.y ),
|
||||
Math.atan2( point.x, point.z ),
|
||||
Math.atan2( point.y, point.x )
|
||||
]
|
||||
var angle = Math.radToDeg( rotations[axisNumber] )
|
||||
point.removeEuler(worldRotation);
|
||||
|
||||
if (scope.axis == 'E') {
|
||||
let matrix = new THREE.Matrix4().copy(_gizmo[ _mode ].activePlane.matrix).invert();
|
||||
point.applyMatrix4(matrix)
|
||||
var angle = Math.radToDeg( Math.atan2( point.y, point.x ) )
|
||||
rotate_normal = Preview.selected.camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(-1);
|
||||
|
||||
} else {
|
||||
var rotations = [
|
||||
Math.atan2( point.z, point.y ),
|
||||
Math.atan2( point.x, point.z ),
|
||||
Math.atan2( point.y, point.x )
|
||||
]
|
||||
var angle = Math.radToDeg( rotations[axisNumber] )
|
||||
}
|
||||
}
|
||||
let transform_space = Transformer.getTransformSpace()
|
||||
|
||||
@ -1226,6 +1240,9 @@
|
||||
beforeFirstChange(event)
|
||||
|
||||
var difference = angle - previousValue
|
||||
if (axisNumber == undefined) {
|
||||
axisNumber = rotate_normal;
|
||||
}
|
||||
rotateOnAxis(n => (n + difference), axisNumber)
|
||||
Canvas.updatePositions(true)
|
||||
scope.updateSelection()
|
||||
@ -1354,10 +1371,12 @@
|
||||
} else {
|
||||
let {mesh} = Group.selected;
|
||||
|
||||
if (Toolbox.selected.id === 'rotate_tool' && BarItems.rotation_space.value === 'global') {
|
||||
if (axisNumber != 2) difference *= -1;
|
||||
if (Toolbox.selected.id === 'rotate_tool' && (BarItems.rotation_space.value === 'global' || scope.axis == 'E')) {
|
||||
|
||||
let normal = axisNumber == 0 ? THREE.NormalX : (axisNumber == 1 ? THREE.NormalY : THREE.NormalZ)
|
||||
let normal = scope.axis == 'E'
|
||||
? rotate_normal
|
||||
: axisNumber == 0 ? THREE.NormalX : (axisNumber == 1 ? THREE.NormalY : THREE.NormalZ);
|
||||
if (axisNumber != 2) difference *= -1;
|
||||
let rotWorldMatrix = new THREE.Matrix4();
|
||||
rotWorldMatrix.makeRotationAxis(normal, Math.degToRad(difference))
|
||||
rotWorldMatrix.multiply(mesh.matrixWorld)
|
||||
@ -1426,7 +1445,7 @@
|
||||
var channel = Toolbox.selected.animation_channel
|
||||
if (channel === 'position') channel = 'translation';
|
||||
var value = point[axis]
|
||||
var bf = Project.display_settings[display_slot][channel][axisNumber] - (previousValue||0)
|
||||
var bf = (Project.display_settings[display_slot][channel][axisNumber] - (previousValue||0)) || 0;
|
||||
|
||||
if (channel === 'rotation') {
|
||||
value = Math.trimDeg(bf + Math.round(angle*4)/4) - bf;
|
||||
@ -1451,10 +1470,26 @@
|
||||
if (value !== previousValue) {
|
||||
beforeFirstChange(event)
|
||||
|
||||
var difference = value - (previousValue||0)
|
||||
Project.display_settings[display_slot][channel][axisNumber] += difference
|
||||
var difference = value - (previousValue||0);
|
||||
|
||||
if (event.shiftKey && channel === 'scale') {
|
||||
if (channel === 'rotation' && scope.axis == 'E') {
|
||||
let normal = scope.axis == 'E'
|
||||
? rotate_normal
|
||||
: axisNumber == 0 ? THREE.NormalX : (axisNumber == 1 ? THREE.NormalY : THREE.NormalZ);
|
||||
|
||||
let quaternion = display_base.getWorldQuaternion(new THREE.Quaternion()).invert()
|
||||
normal.applyQuaternion(quaternion)
|
||||
display_base.rotateOnAxis(normal, Math.degToRad(difference))
|
||||
|
||||
Project.display_settings[display_slot][channel][0] = Math.roundTo(Math.radToDeg(display_base.rotation.x), 2);
|
||||
Project.display_settings[display_slot][channel][1] = Math.roundTo(Math.radToDeg(display_base.rotation.y) * (display_slot.includes('lefthand') ? -1 : 1), 2);
|
||||
Project.display_settings[display_slot][channel][2] = Math.roundTo(Math.radToDeg(display_base.rotation.z) * (display_slot.includes('lefthand') ? -1 : 1), 2);
|
||||
|
||||
} else {
|
||||
Project.display_settings[display_slot][channel][axisNumber] += difference;
|
||||
}
|
||||
|
||||
if ((event.shiftKey || Pressing.overrides.shift) && channel === 'scale') {
|
||||
var val = Project.display_settings[display_slot][channel][axisNumber]
|
||||
Project.display_settings[display_slot][channel][(axisNumber+1)%3] = val
|
||||
Project.display_settings[display_slot][channel][(axisNumber+2)%3] = val
|
||||
|
@ -728,8 +728,8 @@ BARS.defineActions(function() {
|
||||
min: 0, max: 360, default: 0,
|
||||
},
|
||||
getInterval(e) {
|
||||
if (e.shiftKey) return 12.5;
|
||||
if (e.ctrlOrCmd) return 1;
|
||||
if (e.shiftKey || Pressing.overrides.shift) return 12.5;
|
||||
if (e.ctrlOrCmd || Pressing.overrides.ctrl) return 1;
|
||||
return 4
|
||||
},
|
||||
get: function() {
|
||||
@ -748,8 +748,8 @@ BARS.defineActions(function() {
|
||||
min: 0, max: 100, default: 0,
|
||||
},
|
||||
getInterval(e) {
|
||||
if (e.shiftKey) return 10;
|
||||
if (e.ctrlOrCmd) return 1;
|
||||
if (e.shiftKey || Pressing.overrides.shift) return 10;
|
||||
if (e.ctrlOrCmd || Pressing.overrides.ctrl) return 1;
|
||||
return 2
|
||||
},
|
||||
get: function() {
|
||||
@ -768,8 +768,8 @@ BARS.defineActions(function() {
|
||||
min: 0, max: 100, default: 100,
|
||||
},
|
||||
getInterval(e) {
|
||||
if (e.shiftKey) return 10;
|
||||
if (e.ctrlOrCmd) return 1;
|
||||
if (e.shiftKey || Pressing.overrides.shift) return 10;
|
||||
if (e.ctrlOrCmd || Pressing.overrides.ctrl) return 1;
|
||||
return 2
|
||||
},
|
||||
get: function() {
|
||||
|
@ -187,12 +187,12 @@ const Painter = {
|
||||
Painter.painting = true;
|
||||
|
||||
if (data) {
|
||||
var is_line = event.shiftKey && Painter.current.cube == data.element && Painter.current.face == data.face
|
||||
var is_line = (event.shiftKey || Pressing.overrides.shift) && Painter.current.cube == data.cube && Painter.current.face == data.face
|
||||
Painter.current.cube = data.element;
|
||||
Painter.current.face = data.face;
|
||||
} else {
|
||||
//uv editor
|
||||
var is_line = event.shiftKey;
|
||||
var is_line = (event.shiftKey || Pressing.overrides.shift);
|
||||
}
|
||||
|
||||
if (is_line) {
|
||||
@ -528,7 +528,7 @@ const Painter = {
|
||||
let diff_x = x - Painter.startPixel[0];
|
||||
let diff_y = y - Painter.startPixel[1];
|
||||
|
||||
if (event.shiftKey) {
|
||||
if (event.shiftKey || Pressing.overrides.shift) {
|
||||
let clamp = Math.floor((Math.abs(diff_x) + Math.abs(diff_y))/2);
|
||||
diff_x = diff_x>0 ? clamp : -clamp;
|
||||
diff_y = diff_y>0 ? clamp : -clamp;
|
||||
@ -643,7 +643,7 @@ const Painter = {
|
||||
let diff_x = x - Painter.startPixel[0];
|
||||
let diff_y = y - Painter.startPixel[1];
|
||||
|
||||
if (event.shiftKey) {
|
||||
if (event.shiftKey || Pressing.overrides.shift) {
|
||||
let length = Math.sqrt(Math.pow(diff_x, 2) + Math.pow(diff_y, 2));
|
||||
|
||||
let ratio = Math.abs(diff_x) / Math.abs(diff_y);
|
||||
|
@ -1223,7 +1223,7 @@ function loadTextureDraggable() {
|
||||
Undo.initEdit({elements: cubes_list})
|
||||
cubes_list.forEach(cube => {
|
||||
if (cube instanceof Cube) {
|
||||
cube.applyTexture(tex, data.shiftKey || [data.face])
|
||||
cube.applyTexture(tex, data.shiftKey || Pressing.overrides.shift || [data.face])
|
||||
}
|
||||
})
|
||||
Undo.finishEdit('Apply texture')
|
||||
|
@ -258,7 +258,7 @@ class UVEditor {
|
||||
var offset = scope.jquery.frame.offset();
|
||||
event.offsetX = event.clientX - offset.left;
|
||||
event.offsetY = event.clientY - offset.top;
|
||||
if (!dragging_not_clicking && event.ctrlOrCmd) {
|
||||
if (!dragging_not_clicking && (event.ctrlOrCmd || Pressing.overrides.ctrl)) {
|
||||
scope.reverseSelect(event)
|
||||
}
|
||||
dragging_not_clicking = false;
|
||||
@ -1787,7 +1787,7 @@ const uv_dialog = {
|
||||
BARS.updateConditions()
|
||||
},
|
||||
select: function(id, event) {
|
||||
if (event.shiftKey) {
|
||||
if (event.shiftKey || Pressing.overrides.shift) {
|
||||
uv_dialog.selection.push(id)
|
||||
} else {
|
||||
if (uv_dialog.selection.includes(id) && uv_dialog.selection.length === 1) {
|
||||
|
@ -755,7 +755,7 @@ function rotateOnAxis(modify, axis, slider) {
|
||||
}
|
||||
}
|
||||
var axis_letter = getAxisLetter(axis)
|
||||
var origin =things[0].origin
|
||||
var origin = things[0].origin
|
||||
things.forEach(function(obj, i) {
|
||||
if (!obj.rotation.allEqual(0)) {
|
||||
origin = obj.origin
|
||||
@ -763,6 +763,7 @@ function rotateOnAxis(modify, axis, slider) {
|
||||
})
|
||||
|
||||
let space = Transformer.getTransformSpace()
|
||||
if (axis instanceof THREE.Vector3) space = 0;
|
||||
things.forEach(obj => {
|
||||
let mesh = obj.mesh;
|
||||
if (obj instanceof Cube && !Format.bone_rig) {
|
||||
@ -821,7 +822,9 @@ function rotateOnAxis(modify, axis, slider) {
|
||||
obj.rotation[2] = Math.radToDeg(e.z);
|
||||
|
||||
} else if (space == 0) {
|
||||
let normal = axis == 0 ? THREE.NormalX : (axis == 1 ? THREE.NormalY : THREE.NormalZ)
|
||||
let normal = axis instanceof THREE.Vector3
|
||||
? axis
|
||||
: axis == 0 ? THREE.NormalX : (axis == 1 ? THREE.NormalY : THREE.NormalZ)
|
||||
let rotWorldMatrix = new THREE.Matrix4();
|
||||
rotWorldMatrix.makeRotationAxis(normal, Math.degToRad(modify(0)))
|
||||
rotWorldMatrix.multiply(mesh.matrixWorld)
|
||||
|
21
js/util.js
21
js/util.js
@ -1,14 +1,18 @@
|
||||
//Blockbench
|
||||
function compareVersions(string1/*new*/, string2/*old*/) {
|
||||
// Is string1 newer than string2 ?
|
||||
var arr1 = string1.split('.')
|
||||
var arr2 = string2.split('.')
|
||||
var arr1 = string1.split(/[.-]/);
|
||||
var arr2 = string2.split(/[.-]/);
|
||||
var i = 0;
|
||||
var num1 = 0;
|
||||
var num2 = 0;
|
||||
while (i < arr1.length) {
|
||||
num1 = parseInt(arr1[i])
|
||||
num2 = parseInt(arr2[i])
|
||||
while (i < Math.max(arr1.length, arr2.length)) {
|
||||
num1 = arr1[i];
|
||||
num2 = arr2[i];
|
||||
if (num1 == 'beta') num1 = -1;
|
||||
if (num2 == 'beta') num2 = -1;
|
||||
num1 = parseInt(num1) || 0;
|
||||
num2 = parseInt(num2) || 0;
|
||||
if (num1 > num2) {
|
||||
return true;
|
||||
} else if (num1 < num2) {
|
||||
@ -563,6 +567,13 @@ var Merge = {
|
||||
}
|
||||
}
|
||||
|
||||
function onVueSetup(func) {
|
||||
if (!onVueSetup.funcs) {
|
||||
onVueSetup.funcs = []
|
||||
}
|
||||
onVueSetup.funcs.push(func)
|
||||
}
|
||||
|
||||
//String
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
|
File diff suppressed because one or more lines are too long
@ -4,6 +4,7 @@
|
||||
"preview_rotate": {"key": 2},
|
||||
"preview_drag": {"key": 2, "shift": true},
|
||||
"preview_zoom": {"key": 2, "ctrl": true},
|
||||
"preview_area_select": {"key": 1},
|
||||
"confirm": {"key": 13},
|
||||
"cancel": {"key": 27},
|
||||
"move_tool": {"key": 71},
|
||||
|
@ -4,6 +4,7 @@
|
||||
"preview_rotate": {"key": 1, "alt": true},
|
||||
"preview_drag": {"key": 2, "alt": true},
|
||||
"preview_zoom": {"key": 1, "shift": true},
|
||||
"preview_area_select": {"key": 1},
|
||||
"confirm": {"key": 13},
|
||||
"cancel": {"key": 27},
|
||||
"move_tool": {"key": 69},
|
||||
|
@ -4,6 +4,7 @@
|
||||
"preview_rotate": {"key": 1, "alt": true},
|
||||
"preview_drag": {"key": 2, "alt": true},
|
||||
"preview_zoom": {"key": 3, "alt": true},
|
||||
"preview_area_select": {"key": 1},
|
||||
"confirm": {"key": 13},
|
||||
"cancel": {"key": 27},
|
||||
"move_tool": {"key": 87},
|
||||
|
12
lang/en.json
12
lang/en.json
@ -24,6 +24,8 @@
|
||||
"data.preview": "Preview",
|
||||
"data.toolbar": "Toolbar",
|
||||
"data.separator": "Separator",
|
||||
"data.separator.spacer": "Spacer",
|
||||
"data.separator.linebreak": "Line Break",
|
||||
"data.image": "Image",
|
||||
"data.format": "Format",
|
||||
"data.effect": "Effect",
|
||||
@ -341,6 +343,7 @@
|
||||
"dialog.toolbar_edit.title": "Customize Toolbar",
|
||||
"dialog.toolbar_edit.hidden": "Hidden",
|
||||
"dialog.toolbar_edit.hidden_tools": "Some tools might be hidden because they are not available in the current mode, format, or situation.",
|
||||
"dialog.toolbar_edit.incompatible_separators": "Spacers and Line Breaks are mutually exclusive, you cannot use both in the same toolbar.",
|
||||
|
||||
"dialog.entitylist.title": "Open Entity Model",
|
||||
"dialog.entitylist.text": "Select the model you want to import",
|
||||
@ -431,7 +434,6 @@
|
||||
"dialog.export_private_settings.keep": "Keep",
|
||||
"dialog.export_private_settings.omit": "Leave Out",
|
||||
|
||||
"dialog.settings.title": "Preferences",
|
||||
"dialog.settings.settings": "Settings",
|
||||
"dialog.settings.keybinds": "Keybindings",
|
||||
"dialog.settings.theme": "Theme",
|
||||
@ -443,6 +445,11 @@
|
||||
"keybindings.recording": "Recording Keybinding",
|
||||
"keybindings.press": "Press a key or key combination or click anywhere on the screen to record your keybinding.",
|
||||
|
||||
"layout.discover": "Discover",
|
||||
"layout.color": "Color Scheme",
|
||||
"layout.fonts": "Fonts",
|
||||
"layout.css": "Custom CSS",
|
||||
"layout.documentation": "Documentation",
|
||||
"layout.color.back": "Back",
|
||||
"layout.color.back.desc": "Backgrounds and input fields",
|
||||
"layout.color.dark": "Dark",
|
||||
@ -478,7 +485,6 @@
|
||||
"layout.font.main": "Main Font",
|
||||
"layout.font.headline": "Headline Font",
|
||||
"layout.font.code": "Code Font",
|
||||
"layout.css": "Custom CSS",
|
||||
|
||||
"about.version": "Version:",
|
||||
"about.version.up_to_date": "Up to date",
|
||||
@ -486,7 +492,6 @@
|
||||
"about.creator": "Creator:",
|
||||
"about.website": "Website:",
|
||||
"about.repository": "Repository:",
|
||||
"about.electron": "This app is built with Electron, a framework for creating native applications with web technologies like Javascript, HTML, and CSS.",
|
||||
"about.vertex_snap": "Vertex Snapping is based on a plugin by SirBenet",
|
||||
"about.icons": "Icon Packs:",
|
||||
"about.libraries": "Libraries:",
|
||||
@ -666,6 +671,7 @@
|
||||
"keybind.preview_rotate": "Rotate View",
|
||||
"keybind.preview_drag": "Drag View",
|
||||
"keybind.preview_zoom": "Zoom View",
|
||||
"keybind.preview_area_select": "Area Select",
|
||||
"keybind.confirm": "Confirm",
|
||||
"keybind.cancel": "Cancel",
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Blockbench",
|
||||
"description": "Model editing and animation software",
|
||||
"version": "3.9.2",
|
||||
"version": "4.0.0-beta.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"author": {
|
||||
"name": "JannisX11",
|
||||
|
Loading…
x
Reference in New Issue
Block a user