git-svn-id: svn://db.shs.com.ru/libs@626 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
405
qglengine/widgets/scene_tree.cpp
Normal file
405
qglengine/widgets/scene_tree.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
Stanley Designer
|
||||
Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "scene_tree.h"
|
||||
#include "ui_scene_tree.h"
|
||||
#include "glcamera.h"
|
||||
#include "qglview.h"
|
||||
#include <QTreeWidget>
|
||||
#include <QScrollBar>
|
||||
#include <QAction>
|
||||
#include <QEvent>
|
||||
|
||||
enum Column {
|
||||
cName,
|
||||
cVis,
|
||||
cMaterial
|
||||
};
|
||||
enum ItemRole {
|
||||
irObject = Qt::UserRole,
|
||||
irType = Qt::UserRole + 1,
|
||||
};
|
||||
|
||||
enum ObjectType {
|
||||
otNode = 1,
|
||||
otMesh = 2,
|
||||
otLight = 4,
|
||||
otCamera = 8,
|
||||
};
|
||||
|
||||
|
||||
SceneTree::SceneTree(QWidget * parent): QWidget(parent) {
|
||||
ui = new Ui::SceneTree();
|
||||
ui->setupUi(this);
|
||||
ui->treeObjects->header()->setSectionResizeMode(cVis, QHeaderView::ResizeToContents);
|
||||
ui->treeObjects->header()->setSectionsMovable(false);
|
||||
ui->treeObjects->header()->swapSections(cName, cVis);
|
||||
icon_empty = QIcon(":/icons/type-empty.png");
|
||||
icon_geo = QIcon(":/icons/type-geo.png");
|
||||
icon_camera = QIcon(":/icons/type-camera.png");
|
||||
icon_light = QIcon(":/icons/type-light.png");
|
||||
icon_vis[0] = QIcon(":/icons/layer-visible-off.png");
|
||||
icon_vis[1] = QIcon(":/icons/layer-visible-on.png");
|
||||
QAction * a = 0;
|
||||
a = new QAction(QIcon(":/icons/type-camera.png"), "Focus");
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(focusObjects()));
|
||||
ui->treeObjects->addAction(a);
|
||||
a = new QAction(QIcon(":/icons/edit-delete.png"), "Remove");
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(removeObjects()));
|
||||
ui->treeObjects->addAction(a);
|
||||
view = 0;
|
||||
block_tree = false;
|
||||
connect(ui->treeObjects->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(treeObjects_selectionCnahged()));
|
||||
}
|
||||
|
||||
|
||||
SceneTree::~SceneTree() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::assignQGLView(QGLView * v) {
|
||||
view = v;
|
||||
connect(view, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
|
||||
connect(view, SIGNAL(materialsChanged()), this, SLOT(materialsChanged()));
|
||||
connect(view->scene(), SIGNAL(treeChanged()), this, SLOT(objectsTreeChanged()));
|
||||
connect(view->scene(), SIGNAL(__objectDeleted(ObjectBase*)), this, SLOT(__objectDeleted(ObjectBase*)));
|
||||
objectsTreeChanged();
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::changeEvent(QEvent * e) {
|
||||
QWidget::changeEvent(e);
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
ui->retranslateUi(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::rememberExpanded(QTreeWidgetItem * ti) {
|
||||
for (int i = 0; i < ti->childCount(); ++i) {
|
||||
QTreeWidgetItem * ci = ti->child(i);
|
||||
if (ci->isExpanded())
|
||||
expanded_ << itemObject(ci);
|
||||
rememberExpanded(ci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::restoreExpanded(QTreeWidgetItem * ti) {
|
||||
for (int i = 0; i < ti->childCount(); ++i) {
|
||||
QTreeWidgetItem * ci = ti->child(i);
|
||||
ci->setExpanded(expanded_.contains(itemObject(ci)));
|
||||
restoreExpanded(ci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::makeObjetTree(ObjectBase * o, QTreeWidgetItem * ti) {
|
||||
for (int i = 0; i < o->childCount(); ++i) {
|
||||
ObjectBase * co = o->child(i);
|
||||
QTreeWidgetItem * ci = new QTreeWidgetItem(ti);
|
||||
ci->setText(cName, co->name());
|
||||
ci->setCheckState(cVis, co->isVisible() ? Qt::Checked : Qt::Unchecked);
|
||||
ci->setIcon(cVis, icon_vis[co->isVisible(true)]);
|
||||
if (co->material())
|
||||
ci->setText(cMaterial, co->material()->name);
|
||||
ci->setFlags(ci->flags() | Qt::ItemIsEditable);
|
||||
ObjectType t = otNode;
|
||||
switch (co->type()) {
|
||||
case ObjectBase::glMesh:
|
||||
if (co->mesh()) {
|
||||
t = otMesh;
|
||||
ci->setIcon(cName, icon_geo);
|
||||
geo_items << ci;
|
||||
} else {
|
||||
ci->setIcon(cName, icon_empty);
|
||||
}
|
||||
break;
|
||||
case ObjectBase::glLight:
|
||||
t = otLight;
|
||||
ci->setIcon(cName, icon_light);
|
||||
break;
|
||||
case ObjectBase::glCamera:
|
||||
t = otCamera;
|
||||
ci->setIcon(cName, icon_camera);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
ci->setData(cName, irObject, quintptr(co));
|
||||
ci->setData(cName, irType, int(t));
|
||||
ci->setSelected(co->isSelected());
|
||||
makeObjetTree(co, ci);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ObjectBase * SceneTree::itemObject(QTreeWidgetItem * item) const {
|
||||
if (!item) return 0;
|
||||
return (ObjectBase*)(item->data(cName, irObject).toULongLong());
|
||||
}
|
||||
|
||||
|
||||
int SceneTree::itemType(QTreeWidgetItem * item) const {
|
||||
if (!item) return otNode;
|
||||
return item->data(cName, irType).toInt();
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::selectionChanged() {
|
||||
if (block_tree) return;
|
||||
block_tree = true;
|
||||
QList<QTreeWidgetItem*> il = ui->treeObjects->findItems("", Qt::MatchContains | Qt::MatchRecursive);
|
||||
const ObjectBase * fo = 0;
|
||||
if (view->selectedObjects().size() == 1)
|
||||
fo = view->selectedObject();
|
||||
foreach (QTreeWidgetItem * i, il) {
|
||||
ObjectBase * o = itemObject(i);
|
||||
i->setSelected(o->isSelected());
|
||||
if (fo && (fo == o)) {
|
||||
ui->treeObjects->setCurrentItem(i);
|
||||
}
|
||||
}
|
||||
block_tree = false;
|
||||
checkButtons();
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::materialsChanged() {
|
||||
foreach (QTreeWidgetItem * i, geo_items) {
|
||||
ObjectBase * o = itemObject(i);
|
||||
if (!o) continue;
|
||||
if (o->material())
|
||||
i->setText(cMaterial, o->material()->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SceneTree::filterTree(QTreeWidgetItem * ti, const QString & filter, int types) {
|
||||
bool ret = false;
|
||||
for (int i = 0; i < ti->childCount(); ++i) {
|
||||
QTreeWidgetItem * ci = ti->child(i);
|
||||
QString cit = ci->text(cName);
|
||||
int t = itemType(ci);
|
||||
if (ci->childCount() > 0) {
|
||||
if (!filterTree(ci, filter, types)) {
|
||||
ci->setHidden(true);
|
||||
continue;
|
||||
}
|
||||
ci->setHidden(false);
|
||||
ret = true;
|
||||
} else {
|
||||
bool f = false;
|
||||
if (filter.isEmpty()) {
|
||||
f = true;
|
||||
} else {
|
||||
f = f || cit.contains(filter);
|
||||
}
|
||||
if ((types & t) != t)
|
||||
f = false;
|
||||
ci->setHidden(!f);
|
||||
if (f) ret = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::checkButtons() {
|
||||
bool has_1 = false, has_m = false;
|
||||
if (view) {
|
||||
has_1 = !view->selectedObjects().isEmpty();
|
||||
has_m = view->selectedObjects().size() > 1;
|
||||
}
|
||||
ui->buttonFocus ->setEnabled(has_1);
|
||||
ui->buttonRemove->setEnabled(has_1);
|
||||
ui->buttonClone ->setEnabled(has_1);
|
||||
ui->buttonSelectParent->setEnabled(has_1);
|
||||
ui->buttonGroup->setEnabled(has_m);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::treeObjects_selectionCnahged() {
|
||||
if (block_tree || !view) return;
|
||||
block_tree = true;
|
||||
view->scene()->clearSelection();
|
||||
QList<ObjectBase*> sol;
|
||||
QList<QTreeWidgetItem*> til = ui->treeObjects->selectedItems();
|
||||
foreach (QTreeWidgetItem * i, til)
|
||||
sol << itemObject(i);
|
||||
view->scene()->selectObjects(sol);
|
||||
block_tree = false;
|
||||
checkButtons();
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::filter() {
|
||||
int types = 0;
|
||||
if (ui->buttonFilterNode ->isChecked()) types |= otNode ;
|
||||
if (ui->buttonFilterMesh ->isChecked()) types |= otMesh ;
|
||||
if (ui->buttonFilterLight ->isChecked()) types |= otLight ;
|
||||
if (ui->buttonFilterCamera->isChecked()) types |= otCamera;
|
||||
if (types == 0) types = 0xFF;
|
||||
filterTree(ui->treeObjects->invisibleRootItem(), ui->lineFilter->text(), types);
|
||||
ui->treeObjects->invisibleRootItem()->setHidden(false);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::__objectDeleted(ObjectBase * o) {
|
||||
for (int i = 0; i < geo_items.size(); ++i)
|
||||
if (itemObject(geo_items[i]) == o) {
|
||||
geo_items.removeAt(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_treeObjects_itemChanged(QTreeWidgetItem * item, int column) {
|
||||
if (block_tree) return;
|
||||
if (column == cName) {
|
||||
ObjectBase * o = itemObject(item);
|
||||
if (o) o->setName(item->text(cName));
|
||||
}
|
||||
if (column == cVis) {
|
||||
bool vis = item->checkState(cVis) == Qt::Checked;
|
||||
QList<QTreeWidgetItem*> til = ui->treeObjects->selectedItems();
|
||||
if (!til.contains(item)) {
|
||||
til.clear();
|
||||
til << item;
|
||||
}
|
||||
foreach (QTreeWidgetItem * ti, til) {
|
||||
//itemObject(ti)->setVisible(vis);
|
||||
itemObject(ti)->setVisible(vis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_treeObjects_itemMoved(QTreeWidgetItem * item, QTreeWidgetItem * new_parent) {
|
||||
ObjectBase * co = itemObject(item);
|
||||
if (!co->hasParent()) return;
|
||||
//co->parent()->removeChild(co);
|
||||
if (new_parent == ui->treeObjects->invisibleRootItem()) {
|
||||
view->scene()->rootObject()->addChild(co);
|
||||
} else {
|
||||
ObjectBase * po = itemObject(new_parent);
|
||||
if (po)
|
||||
po->addChild(co);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_buttonAddNode_clicked() {
|
||||
if (!view) return;
|
||||
ObjectBase * no = new ObjectBase();
|
||||
view->scene()->addObject(no);
|
||||
view->scene()->selectObject(no);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_buttonAddLight_clicked() {
|
||||
if (!view) return;
|
||||
ObjectBase * no = new Light();
|
||||
view->scene()->addObject(no);
|
||||
view->scene()->selectObject(no);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_buttonClone_clicked() {
|
||||
if (!view) return;
|
||||
QList<QTreeWidgetItem*> sil = ui->treeObjects->selectedItems();
|
||||
QList<ObjectBase*> col;
|
||||
foreach (QTreeWidgetItem * i, sil) {
|
||||
ObjectBase * o = itemObject(i);
|
||||
if (!o) continue;
|
||||
ObjectBase * no = o->clone();
|
||||
o->parent()->addChild(no);
|
||||
col << no;
|
||||
}
|
||||
view->scene()->selectObjects(col);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_buttonSelectParent_clicked() {
|
||||
if (!view) return;
|
||||
QList<ObjectBase*> sol = view->scene()->selectedObjects(true);
|
||||
QSet<ObjectBase*> nsl;
|
||||
foreach (ObjectBase * o, sol) {
|
||||
ObjectBase * po = o->parent();
|
||||
if (po != view->scene()->rootObject())
|
||||
o = po;
|
||||
nsl << o;
|
||||
}
|
||||
view->scene()->selectObjects(nsl.toList());
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::on_buttonGroup_clicked() {
|
||||
if (!view) return;
|
||||
QList<ObjectBase*> sol = view->scene()->selectedObjects(true);
|
||||
ObjectBase * cp = sol[0]->parent();
|
||||
ObjectBase * nr = new ObjectBase();
|
||||
cp->addChild(nr);
|
||||
foreach (ObjectBase * o, sol)
|
||||
nr->addChild(o);
|
||||
view->scene()->selectObject(nr);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::removeObjects() {
|
||||
if (!view) return;
|
||||
QList<QTreeWidgetItem*> sil = ui->treeObjects->selectedItems();
|
||||
foreach (QTreeWidgetItem * i, sil) {
|
||||
ObjectBase * o = itemObject(i);
|
||||
if (o) delete o;
|
||||
}
|
||||
qDeleteAll(sil);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::focusObjects() {
|
||||
if (!view) return;
|
||||
if (!view->camera()) return;
|
||||
Box3D bb;
|
||||
QList<ObjectBase*> ol = view->selectedObjects();
|
||||
foreach (ObjectBase * o, ol) {
|
||||
o->calculateBoundingBox();
|
||||
bb |= o->boundingBox();
|
||||
}
|
||||
view->focusOn(bb);
|
||||
}
|
||||
|
||||
|
||||
void SceneTree::objectsTreeChanged() {
|
||||
int vpos = ui->treeObjects->verticalScrollBar()->value();
|
||||
expanded_.clear();
|
||||
geo_items.clear();
|
||||
rememberExpanded(ui->treeObjects->invisibleRootItem());
|
||||
block_tree = true;
|
||||
ui->treeObjects->clear();
|
||||
block_tree = false;
|
||||
if (!view) return;
|
||||
block_tree = true;
|
||||
makeObjetTree(view->scene()->rootObject(), ui->treeObjects->invisibleRootItem());
|
||||
restoreExpanded(ui->treeObjects->invisibleRootItem());
|
||||
block_tree = false;
|
||||
filter();
|
||||
QApplication::processEvents();
|
||||
ui->treeObjects->verticalScrollBar()->setValue(vpos);
|
||||
}
|
||||
Reference in New Issue
Block a user