Skip to content

Commit

Permalink
Implement treewidget in query editor
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderMertens committed May 22, 2024
1 parent efc150e commit 95fb984
Show file tree
Hide file tree
Showing 11 changed files with 435 additions and 7 deletions.
2 changes: 0 additions & 2 deletions etc/v4/js/entity_tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,6 @@ Vue.component('entity-tree', {
path = elem.parent + "." + name_esc
}

console.log(path);

let label;
let color;
if (elem.entity_labels) {
Expand Down
1 change: 1 addition & 0 deletions etc/v4/query_editor/css/colors.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
--grey-200: rgb(237, 237, 237);

--dark-blue: #00346E;
--less-dark-blue: #094a94;
--green: #42b983;
--blue: rgb(103, 154, 209);
--purple: rgb(188, 137, 189);
Expand Down
16 changes: 15 additions & 1 deletion etc/v4/query_editor/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@
<body>
<div id="app">
<menu-bar
:items="['queries', 'commands', 'info']">
:items="['entities', 'queries', 'commands', 'info']">
<template v-slot:entities>
<menu-button
name="entities"
img="list-tree"
v-model:page="page">
</menu-button>
</template>
<template v-slot:queries>
<menu-button
name="queries"
Expand All @@ -37,6 +44,13 @@
</template>
</menu-bar>

<template v-if="page == 'entities'">
<page-entities
:conn="conn"
v-model:app_state="app_state">
</page-entities>
</template>

<template v-if="page == 'queries'">
<page-queries
:conn="conn"
Expand Down
8 changes: 8 additions & 0 deletions etc/v4/query_editor/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ let components = [
loadModule('js/components/entity-parent.vue', options),
loadModule('js/components/entity-name.vue', options),

// Entities page
loadModule('js/components/pages/entities/page.vue', options),
loadModule('js/components/pages/entities/pane-tree.vue', options),
loadModule('js/components/pages/entities/entity-tree.vue', options),
loadModule('js/components/pages/entities/entity-subtree.vue', options),
loadModule('js/components/pages/entities/entity-tree-item.vue', options),
loadModule('js/components/pages/entities/entity-tree-icon.vue', options),

// Queries page
loadModule('js/components/pages/queries/page.vue', options),
loadModule('js/components/pages/queries/pane-query.vue', options),
Expand Down
14 changes: 10 additions & 4 deletions etc/v4/query_editor/js/components/icon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,26 @@ const props = defineProps({
src: { type: String, required: true },
class: { type: String, required: false, default: ""},
size: { type: Number, required: false, default: 16 },
opacity: { type: Number, required: false, default: 0.7 },
opacity: { type: Number, required: false },
rotate: { type: Number, required: false, default: 0.0 },
});
const style = computed(() => {
return `
let result = `
position: relative;
width: ${props.size}px;
height: ${props.size}px;
opacity: ${props.opacity};
transform: rotate(${props.rotate}deg);
vertical-align: middle;
height: 100%;
height: 100%;`;
if (props.opacity !== undefined) {
result += `
opacity: ${props.opacity};
`;
}
return result;
});
const src = computed(() => {
Expand Down
131 changes: 131 additions & 0 deletions etc/v4/query_editor/js/components/pages/entities/entity-subtree.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<template>
<div class="entity-subtree">
<entity-tree-item
:conn="conn"
:item="item"
:depth="depth"
:selectedItem="selectedItem"
:key="'entity-tree-item-' + item.path"
v-for="item in treeQueryResult"
@select="selectItem">
</entity-tree-item>
<template v-if="path !== '0'">
<div class="entity-tree-vertical-line" :style="lineIndent"></div>
</template>
</div>
</template>

<script>
export default { name: "entity-subtree" }
</script>

<script setup>
import { onMounted, onUnmounted, ref, defineProps, defineEmits, computed } from 'vue';
const props = defineProps({
conn: {type: Object, required: true},
selectedItem: {type: Object, required: false},
path: {type: String, required: false, default: "0"},
depth: {type: Number, required: false, default: 0}
});
const emit = defineEmits(['select']);
const items = ref({});
const lineIndent = computed(() => {
return `margin-left: ${props.depth * 12 - 8}px;`;
});
function selectItem(evt) {
emit('select', evt);
}
const treeQuery = ref();
const treeQueryResult = ref();
onMounted(() => {
const q = `
(ChildOf, ${props.path}),
?Module,
?Component,
?Prefab,
?Disabled,
?ChildOf(_, $this),
?IsA($this, $base|self)`
;
treeQuery.value =
props.conn.query(q, {try: true, rows: true, limit: 1000, poll_interval: 1000}, (reply) => {
let sortedItems = [];
for (let item of reply.results) {
const name = item.name + "";
const name_esc = name.replaceAll(".", "\\.");
let path = name_esc;
if (item.parent) {
path = item.parent + "." + name_esc
}
let treeItem = items[path];
if (treeItem === undefined) {
treeItem = items[path] = {};
}
Object.assign(treeItem, item);
treeItem.path = path;
treeItem.isModule = item.is_set[1];
treeItem.isComponent = item.is_set[2];
treeItem.isPrefab = item.is_set[3];
treeItem.isDisabled = item.is_set[4];
treeItem.isParent = item.is_set[5];
treeItem.baseEntity = item.is_set[6] ? item.vars["base"] : undefined;
sortedItems.push(treeItem);
}
sortedItems.sort((a, b) => {
if (a.isModule == b.isModule) {
if (a.isParent == b.isParent) {
if (a.label) {
return a.label.localeCompare(b.label);
} else {
return a.name.localeCompare(b.name);
}
} else if (a.isParent) {
return -1;
} else {
return 1;
}
} else if (a.isModule) {
return -1;
} else {
return 1;
}
});
treeQueryResult.value = sortedItems;
});
});
onUnmounted(() => {
treeQuery.value.abort();
});
</script>

<style scoped>
div.entity-subtree {
position: relative;
}
div.entity-tree-vertical-line {
position: absolute;
top: 2px;
left: 4px;
min-width: 1px;
height: calc(100% - 4px);
background-color: white;
opacity: 0.2;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<svg width="8" height="20">
<circle
cx="4"
cy="11"
r="4"
:fill="fillColor">
</circle>
</svg>
</template>

<script>
export default { name: "entity-tree-icon" }
</script>

<script setup>
import { defineProps, computed } from 'vue';
const props = defineProps({
item: {type: Object, required: true}
});
const fillColor = computed(() => {
if (props.item.color) {
return props.item.color;
} else if (props.item.isModule) {
return "#FFE100";
} else if (props.item.isComponent) {
return "#4981B5";
} else if (props.item.isPrefab) {
return "#DDE0E6";
} else {
return "var(--green)";
}
});
</script>

<style scoped>
</style>
131 changes: 131 additions & 0 deletions etc/v4/query_editor/js/components/pages/entities/entity-tree-item.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<template>
<div>
<div :class="itemClass" :style="itemIndent" @click="selectItem">
<template v-if="item.isParent">
<div class="entity-tree-item-chevron" @click.stop="toggleItem">
<icon class="noselect" src="chevron-right" :size="16" v-if="!expand"></icon>
<icon class="noselect" src="chevron-down" :size="16" v-if="expand"></icon>
</div>
</template>
<div class="entity-tree-item-icon">
<entity-tree-icon :item="item"></entity-tree-icon>
</div>
<div class="entity-tree-item-name noselect">
{{ item.name }}
</div>
</div>
<template v-if="expand">
<entity-subtree
:conn="conn"
:path="item.path"
:depth="depth + 1"
:selectedItem="selectedItem"
:key="'entity-subtree-' + item.path"
@select="selectChild">
</entity-subtree>
</template>
</div>
</template>

<script>
export default { name: "entity-tree-item" }
</script>

<script setup>
import { defineProps, computed, ref, defineEmits } from 'vue';
const props = defineProps({
conn: {type: Object, required: true},
item: {type: Object, required: true},
selectedItem: {type: Object, required: false},
depth: {type: Number, required: false, default: 0}
});
const emit = defineEmits(["select"]);
const expand = ref(false);
function toggleItem() {
expand.value = !expand.value;
}
function selectItem() {
if (isSelected.value) {
emit("select", undefined);
} else {
emit("select", props.item);
}
}
function selectChild(evt) {
emit("select", evt);
}
const itemClass = computed(() => {
let result = ["entity-tree-item"];
if (isSelected.value) {
result.push("entity-tree-item-selected");
}
return result;
});
const itemIndent = computed(() => {
return `padding-left: ${props.depth * 12}px;`;
});
const isSelected = computed(() => {
return props.item == props.selectedItem;
});
</script>

<style scoped>
div.entity-tree-item {
position: relative;
display: grid;
grid-template-columns: 18px 14px 1rem;
max-height: 28px;
padding-top: 4px;
cursor: pointer;
border-radius: var(--border-radius-medium);
border-color: rgba(0, 0, 0, 0);
border-width: 1px;
border-style: solid;
}
div.entity-tree-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
div.entity-tree-item-selected {
background-color: var(--dark-blue);
border-color: var(--less-dark-blue);
}
div.entity-tree-item-selected:hover {
background-color: var(--dark-blue);
border-color: var(--less-dark-blue);
}
div.entity-tree-item-chevron {
grid-column: 1;
cursor: pointer;
opacity: 0.7;
}
div.entity-tree-item-icon {
grid-column: 2;
}
div.entity-tree-item-chevron:hover {
opacity: 1.0;
}
div.entity-tree-item-name {
grid-column: 3;
color: var(--primary-text);
}
</style>
Loading

0 comments on commit 95fb984

Please sign in to comment.