-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement treewidget in query editor
- Loading branch information
1 parent
efc150e
commit 95fb984
Showing
11 changed files
with
435 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
etc/v4/query_editor/js/components/pages/entities/entity-subtree.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
40 changes: 40 additions & 0 deletions
40
etc/v4/query_editor/js/components/pages/entities/entity-tree-icon.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
131
etc/v4/query_editor/js/components/pages/entities/entity-tree-item.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
Oops, something went wrong.