feat: geometry spreadsheet
This commit is contained in:
@@ -31,6 +31,9 @@ set(GUI_SOURCES
|
||||
src/Gui/main.cpp
|
||||
src/Gui/Interface.cpp
|
||||
src/Gui/UtilWidgets/Splitter.cpp
|
||||
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetPanel.cpp
|
||||
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetMenuBar.cpp
|
||||
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.cpp
|
||||
src/Gui/Viewport/Viewport.cpp
|
||||
src/Gui/Viewport/ViewportGLWidget.cpp
|
||||
src/Gui/Viewport/GLCamera.cpp
|
||||
|
||||
@@ -35,7 +35,7 @@ enzo::nt::OpId enzo::nt::NetworkManager::addOperator(op::OpInfo opInfo)
|
||||
if(getDisplayOp().has_value() && getDisplayOp().value()==dependentId)
|
||||
{
|
||||
cookOp(dependentId);
|
||||
updateDisplay(dependentOp.getOutputGeo(0));
|
||||
displayGeoChanged(dependentOp.getOutputGeo(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,8 +80,8 @@ void enzo::nt::NetworkManager::setDisplayOp(OpId opId)
|
||||
cookOp(opId);
|
||||
|
||||
enzo::nt::GeometryOperator& displayOp = getGeoOperator(opId);
|
||||
updateDisplay(displayOp.getOutputGeo(0));
|
||||
displayNodeChanged();
|
||||
displayGeoChanged(displayOp.getOutputGeo(0));
|
||||
displayNodeChanged(opId);
|
||||
}
|
||||
|
||||
void enzo::nt::NetworkManager::cookOp(enzo::nt::OpId opId)
|
||||
|
||||
@@ -24,7 +24,8 @@ public:
|
||||
GeometryOperator& getGeoOperator(nt::OpId opId);
|
||||
void setDisplayOp(OpId opId);
|
||||
|
||||
boost::signals2::signal<void ()> displayNodeChanged;
|
||||
boost::signals2::signal<void (nt::OpId)> displayNodeChanged;
|
||||
boost::signals2::signal<void (enzo::geo::Geometry& geometry)> displayGeoChanged;
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
void _reset();
|
||||
@@ -47,9 +48,6 @@ private:
|
||||
std::optional<OpId> displayOp_=std::nullopt;
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
void updateDisplay(enzo::geo::Geometry& geometry);
|
||||
|
||||
};
|
||||
|
||||
inline enzo::nt::NetworkManager& nm() {
|
||||
|
||||
@@ -15,15 +15,19 @@ ga::Attribute::Attribute(std::string name, ga::AttributeType type)
|
||||
{
|
||||
case(AttrType::intT):
|
||||
intStore_=std::make_shared<std::vector<bt::intT>>();
|
||||
typeSize_=1;
|
||||
break;
|
||||
case(AttrType::floatT):
|
||||
floatStore_=std::make_shared<std::vector<bt::floatT>>();
|
||||
typeSize_=1;
|
||||
break;
|
||||
case(AttrType::vectorT):
|
||||
vector3Store_=std::make_shared<std::vector<enzo::bt::Vector3>>();
|
||||
typeSize_=3;
|
||||
break;
|
||||
case(AttrType::boolT):
|
||||
boolStore_=std::make_shared<std::vector<enzo::bt::boolT>>();
|
||||
typeSize_=1;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Type " + std::to_string(static_cast<int>(type_)) + " was not properly accounted for in Attribute constructor");
|
||||
@@ -32,6 +36,13 @@ ga::Attribute::Attribute(std::string name, ga::AttributeType type)
|
||||
|
||||
}
|
||||
|
||||
unsigned int ga::Attribute::Attribute::getTypeSize() const
|
||||
{
|
||||
return typeSize_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ga::Attribute::Attribute(const Attribute& other)
|
||||
{
|
||||
type_ = other.type_;
|
||||
@@ -39,6 +50,7 @@ ga::Attribute::Attribute(const Attribute& other)
|
||||
hidden_ = other.hidden_;
|
||||
readOnly_ = other.readOnly_;
|
||||
name_ = other.name_;
|
||||
typeSize_ = other.typeSize_;
|
||||
|
||||
switch(type_)
|
||||
{
|
||||
@@ -61,12 +73,12 @@ ga::Attribute::Attribute(const Attribute& other)
|
||||
}
|
||||
|
||||
|
||||
ga::AttributeType ga::Attribute::getType()
|
||||
ga::AttributeType ga::Attribute::getType() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
std::string ga::Attribute::getName()
|
||||
std::string ga::Attribute::getName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
@@ -21,13 +21,16 @@ namespace enzo{
|
||||
public:
|
||||
Attribute(std::string name, ga::AttributeType type);
|
||||
Attribute(const Attribute& other);
|
||||
AttributeType getType();
|
||||
std::string getName();
|
||||
AttributeType getType() const;
|
||||
std::string getName() const;
|
||||
unsigned int getTypeSize() const;
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
friend class AttributeHandle;
|
||||
template <typename T>
|
||||
friend class AttributeHandleRO;
|
||||
|
||||
private:
|
||||
// private attributes are attributes that are hidden from the user
|
||||
@@ -40,6 +43,7 @@ namespace enzo{
|
||||
bool readOnly_=false;
|
||||
|
||||
ga::AttributeType type_;
|
||||
unsigned int typeSize_=1;
|
||||
|
||||
std::string name_;
|
||||
|
||||
|
||||
@@ -51,14 +51,15 @@ public:
|
||||
{
|
||||
throw std::runtime_error("Type " + std::to_string(static_cast<int>(type_)) + " was not properly accounted for in AttributeHandle constructor");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addValue(T value)
|
||||
{
|
||||
// TODO:make this private (primitive friend classes only)
|
||||
data_->push_back(value);
|
||||
}
|
||||
|
||||
|
||||
void reserve(std::size_t newCap)
|
||||
{
|
||||
data_->reserve(newCap);
|
||||
@@ -118,4 +119,94 @@ using AttributeHandleFloat = AttributeHandle<bt::floatT>;
|
||||
using AttributeHandleVector3 = AttributeHandle<enzo::bt::Vector3>;
|
||||
using AttributeHandleBool = AttributeHandle<enzo::bt::boolT>;
|
||||
|
||||
template <typename T>
|
||||
class AttributeHandleRO
|
||||
{
|
||||
public:
|
||||
ga::AttributeType type_;
|
||||
|
||||
AttributeHandleRO(std::shared_ptr<const Attribute> attribute)
|
||||
{
|
||||
type_ = attribute->getType();
|
||||
// get attribute data pointer
|
||||
// TODO: check types match
|
||||
// TODO: add the other types
|
||||
|
||||
// int
|
||||
if constexpr (std::is_same<bt::intT, T>::value)
|
||||
{
|
||||
data_=attribute->intStore_;
|
||||
}
|
||||
|
||||
// float
|
||||
else if constexpr (std::is_same<bt::floatT, T>::value)
|
||||
{
|
||||
data_=attribute->floatStore_;
|
||||
}
|
||||
|
||||
// vector 3
|
||||
else if constexpr (std::is_same<enzo::bt::Vector3, T>::value)
|
||||
{
|
||||
data_=attribute->vector3Store_;
|
||||
}
|
||||
else if constexpr (std::is_same<enzo::bt::boolT, T>::value)
|
||||
{
|
||||
data_=attribute->boolStore_;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Type " + std::to_string(static_cast<int>(type_)) + " was not properly accounted for in AttributeHandle constructor");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: replace with iterator
|
||||
std::vector<T> getAllValues() const
|
||||
{
|
||||
return {data_->begin(), data_->end()};
|
||||
}
|
||||
|
||||
size_t getSize() const
|
||||
{
|
||||
return data_->size();
|
||||
}
|
||||
|
||||
T getValue(size_t pos) const
|
||||
{
|
||||
// TODO:protect against invalid positions
|
||||
// TODO: cast types
|
||||
return (*data_)[pos];
|
||||
}
|
||||
|
||||
std::string getName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
// private attributes are attributes that are hidden from the user
|
||||
// for internal use
|
||||
bool private_=false;
|
||||
// hidden attributes are user accessible attributes that the user may
|
||||
// or may want to use
|
||||
bool hidden_=false;
|
||||
// allows the user to read the attributeHandle but not modify it
|
||||
bool readOnly_=false;
|
||||
|
||||
std::string name_="";
|
||||
|
||||
std::shared_ptr<StoreContainer<T>> data_;
|
||||
|
||||
// int typeID_;
|
||||
|
||||
};
|
||||
|
||||
using AttributeHandleInt = AttributeHandle<bt::intT>;
|
||||
using AttributeHandleFloat = AttributeHandle<bt::floatT>;
|
||||
using AttributeHandleVector3 = AttributeHandle<enzo::bt::Vector3>;
|
||||
using AttributeHandleBool = AttributeHandle<enzo::bt::boolT>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Engine/Operator/AttributeHandle.h"
|
||||
#include "Engine/Types.h"
|
||||
#include <memory>
|
||||
#include <oneapi/tbb/spin_mutex.h>
|
||||
#include <oneapi/tbb/task_group.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -33,16 +34,45 @@ geo::Geometry::Geometry(const Geometry& other):
|
||||
posHandlePoint_{enzo::ga::AttributeHandleVector3(getAttribByName(ga::AttrOwner::POINT, "P"))},
|
||||
|
||||
// other
|
||||
soloPoints_{other.soloPoints_}
|
||||
soloPoints_{other.soloPoints_},
|
||||
vertexPrims_{other.vertexPrims_},
|
||||
primStarts_{other.primStarts_},
|
||||
primStartsDirty_{other.primStartsDirty_.load()}
|
||||
{
|
||||
}
|
||||
|
||||
enzo::geo::Geometry& enzo::geo::Geometry::operator=(const enzo::geo::Geometry& rhs) {
|
||||
if (this == &rhs) return *this;
|
||||
|
||||
// attributes
|
||||
pointAttributes_ = deepCopyAttributes(rhs.pointAttributes_);
|
||||
vertexAttributes_ = deepCopyAttributes(rhs.vertexAttributes_);
|
||||
primitiveAttributes_ = deepCopyAttributes(rhs.primitiveAttributes_);
|
||||
globalAttributes_ = deepCopyAttributes(rhs.globalAttributes_);
|
||||
|
||||
// handles
|
||||
vertexCountHandlePrim_ = enzo::ga::AttributeHandleInt(getAttribByName(ga::AttrOwner::PRIMITIVE, "vertexCount"));
|
||||
closedHandlePrim_ = enzo::ga::AttributeHandleBool(getAttribByName(ga::AttrOwner::PRIMITIVE, "closed"));
|
||||
pointOffsetHandleVert_ = enzo::ga::AttributeHandleInt(getAttribByName(ga::AttrOwner::VERTEX, "point"));
|
||||
posHandlePoint_ = enzo::ga::AttributeHandleVector3(getAttribByName(ga::AttrOwner::POINT, "P"));
|
||||
|
||||
// other
|
||||
soloPoints_ = rhs.soloPoints_;
|
||||
vertexPrims_ = rhs.vertexPrims_;
|
||||
primStarts_ = rhs.primStarts_;
|
||||
|
||||
primStartsDirty_.store(rhs.primStartsDirty_.load());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void geo::Geometry::addFace(std::vector<ga::Offset> pointOffsets, bool closed)
|
||||
{
|
||||
const ga::Offset primNum = vertexCountHandlePrim_.getSize();
|
||||
for(ga::Offset pointOffset : pointOffsets)
|
||||
{
|
||||
pointOffsetHandleVert_.addValue(pointOffset);
|
||||
vertexPrims_.push_back(primNum);
|
||||
soloPoints_.erase(pointOffset);
|
||||
}
|
||||
vertexCountHandlePrim_.addValue(pointOffsets.size());
|
||||
@@ -63,6 +93,36 @@ ga::Offset geo::Geometry::getNumSoloPoints() const
|
||||
}
|
||||
|
||||
|
||||
// enzo::geo::attributeIterator geo::Geometry::attributesBegin(const ga::AttributeOwner owner)
|
||||
// {
|
||||
// return getAttributeStore(owner).begin();
|
||||
|
||||
// }
|
||||
|
||||
// enzo::geo::attributeIterator geo::Geometry::attributesEnd(const ga::AttributeOwner owner)
|
||||
// {
|
||||
// return getAttributeStore(owner).end();
|
||||
// }
|
||||
|
||||
const size_t geo::Geometry::getNumAttributes(const ga::AttributeOwner owner) const
|
||||
{
|
||||
return getAttributeStore(owner).size();
|
||||
}
|
||||
|
||||
std::weak_ptr<const ga::Attribute> geo::Geometry::getAttributeByIndex(ga::AttributeOwner owner, unsigned int index) const
|
||||
{
|
||||
auto attribStore = getAttributeStore(owner);
|
||||
if(index>=attribStore.size())
|
||||
{
|
||||
throw std::out_of_range("Attribute index out of range: " + std::to_string(index) + " max size: " + std::to_string(attribStore.size()) + "\n");
|
||||
}
|
||||
return getAttributeStore(owner)[index];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::set<ga::Offset>::const_iterator geo::Geometry::soloPointsBegin()
|
||||
{
|
||||
@@ -89,6 +149,11 @@ bt::Vector3 geo::Geometry::getPointPos(ga::Offset pointOffset) const
|
||||
return posHandlePoint_.getValue(pointOffset);
|
||||
}
|
||||
|
||||
ga::Offset geo::Geometry::getVertexPrim(ga::Offset vertexOffset) const
|
||||
{
|
||||
return vertexPrims_[vertexOffset];
|
||||
}
|
||||
|
||||
void geo::Geometry::setPointPos(const ga::Offset offset, const bt::Vector3& pos)
|
||||
{
|
||||
posHandlePoint_.setValue(offset, pos);
|
||||
@@ -220,19 +285,30 @@ enzo::geo::HeMesh geo::Geometry::computeHalfEdgeMesh()
|
||||
ga::Offset geo::Geometry::getPrimStartVertex(ga::Offset primOffset) const
|
||||
{
|
||||
|
||||
if(primStartsDirty_.load())
|
||||
{
|
||||
tbb::spin_mutex::scoped_lock lock(primStartsMutex_); //lock
|
||||
if(primStartsDirty_.load()) // double check
|
||||
{
|
||||
computePrimStartVertices();
|
||||
}
|
||||
}
|
||||
return primStarts_[primOffset];
|
||||
}
|
||||
|
||||
// TODO: handle this automatically
|
||||
void geo::Geometry::computePrimStartVertices()
|
||||
void geo::Geometry::computePrimStartVertices() const
|
||||
{
|
||||
const ga::Offset handleSize = vertexCountHandlePrim_.getSize();
|
||||
primStarts_.clear();
|
||||
primStarts_.reserve(handleSize);
|
||||
bt::intT primStart = 0;
|
||||
for(size_t i=0; i<handleSize; ++i)
|
||||
{
|
||||
primStarts_.push_back(primStart);
|
||||
primStart += vertexCountHandlePrim_.getValue(i);
|
||||
}
|
||||
primStartsDirty_.store(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -265,7 +341,7 @@ ga::AttributeHandle<bt::Vector3> geo::Geometry::addVector3Attribute(ga::Attribut
|
||||
return ga::AttributeHandle<bt::Vector3>(newAttribute);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ga::Attribute>>& geo::Geometry::getAttributeStore(ga::AttributeOwner& owner)
|
||||
geo::Geometry::attribVector& geo::Geometry::getAttributeStore(const ga::AttributeOwner& owner)
|
||||
{
|
||||
switch(owner)
|
||||
{
|
||||
@@ -286,6 +362,26 @@ std::vector<std::shared_ptr<ga::Attribute>>& geo::Geometry::getAttributeStore(ga
|
||||
}
|
||||
}
|
||||
|
||||
const geo::Geometry::attribVector& geo::Geometry::getAttributeStore(const ga::AttributeOwner& owner) const
|
||||
{
|
||||
switch(owner)
|
||||
{
|
||||
case ga::AttributeOwner::POINT:
|
||||
return pointAttributes_;
|
||||
break;
|
||||
case ga::AttributeOwner::VERTEX:
|
||||
return vertexAttributes_;
|
||||
break;
|
||||
case ga::AttributeOwner::PRIMITIVE:
|
||||
return primitiveAttributes_;
|
||||
break;
|
||||
case ga::AttributeOwner::GLOBAL:
|
||||
return globalAttributes_;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unexpected, owner could not be found");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ga::Attribute> geo::Geometry::getAttribByName(ga::AttributeOwner owner, std::string name)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include "Engine/Operator/AttributeHandle.h"
|
||||
#include <memory>
|
||||
#include <oneapi/tbb/spin_mutex.h>
|
||||
#include <tbb/spin_mutex.h>
|
||||
#include <variant>
|
||||
|
||||
|
||||
@@ -19,16 +22,25 @@ using faceDescriptor = HeMesh::Face_index;
|
||||
using V_index = HeMesh::Vertex_index;
|
||||
using F_index = HeMesh::Face_index;
|
||||
|
||||
using attributeIterator = std::vector<std::shared_ptr<ga::Attribute>>::iterator;
|
||||
|
||||
class Geometry
|
||||
{
|
||||
public:
|
||||
Geometry();
|
||||
Geometry(const Geometry& other);
|
||||
Geometry& operator=(const Geometry& rhs);
|
||||
ga::AttributeHandle<bt::intT> addIntAttribute(ga::AttributeOwner owner, std::string name);
|
||||
ga::AttributeHandleBool addBoolAttribute(ga::AttributeOwner owner, std::string name);
|
||||
ga::AttributeHandle<bt::Vector3> addVector3Attribute(ga::AttributeOwner owner, std::string name);
|
||||
// TODO: return weak ptr
|
||||
std::shared_ptr<ga::Attribute> getAttribByName(ga::AttributeOwner owner, std::string name);
|
||||
|
||||
const size_t getNumAttributes(const ga::AttributeOwner owner) const;
|
||||
std::weak_ptr<const ga::Attribute> getAttributeByIndex(ga::AttributeOwner owner, unsigned int index) const;
|
||||
// attributeIterator attributesBegin(const ga::AttributeOwner owner);
|
||||
// attributeIterator attributesEnd(const ga::AttributeOwner owner);
|
||||
|
||||
std::vector<bt::Vector3> derivePointNormals();
|
||||
HeMesh computeHalfEdgeMesh();
|
||||
void addFace(std::vector<ga::Offset> pointOffsets, bool closed=true);
|
||||
@@ -39,21 +51,23 @@ public:
|
||||
|
||||
void setPointPos(const ga::Offset offset, const bt::Vector3& pos);
|
||||
|
||||
ga::Offset getPrimStartVertex(ga::Offset primOffset) const; // returns the first vertex of the primitive
|
||||
bt::Vector3 getPosFromVert(ga::Offset vertexOffset) const;
|
||||
bt::Vector3 getPointPos(ga::Offset pointOffset) const;
|
||||
unsigned int getPrimVertCount(ga::Offset primOffset) const;
|
||||
ga::Offset getNumPrims() const;
|
||||
ga::Offset getNumVerts() const;
|
||||
ga::Offset getNumPoints() const;
|
||||
ga::Offset getNumSoloPoints() const;
|
||||
ga::Offset getPrimStartVertex(ga::Offset primOffset) const; // returns the first vertex of the primitive
|
||||
bt::Vector3 getPosFromVert(ga::Offset vertexOffset) const;
|
||||
bt::Vector3 getPointPos(ga::Offset pointOffset) const;
|
||||
unsigned int getPrimVertCount(ga::Offset primOffset) const;
|
||||
ga::Offset getVertexPrim(ga::Offset vertexOffset) const;
|
||||
ga::Offset getNumPrims() const;
|
||||
ga::Offset getNumVerts() const;
|
||||
ga::Offset getNumPoints() const;
|
||||
ga::Offset getNumSoloPoints() const;
|
||||
|
||||
bt::boolT isClosed(ga::Offset primOffset) const;
|
||||
|
||||
void computePrimStartVertices();
|
||||
void computePrimStartVertices() const;
|
||||
private:
|
||||
using attribVector = std::vector<std::shared_ptr<ga::Attribute>>;
|
||||
attribVector& getAttributeStore(ga::AttributeOwner& owner);
|
||||
geo::Geometry::attribVector& getAttributeStore(const ga::AttributeOwner& owner);
|
||||
const geo::Geometry::attribVector& getAttributeStore(const ga::AttributeOwner& owner) const;
|
||||
|
||||
attribVector deepCopyAttributes(attribVector source);
|
||||
|
||||
@@ -64,7 +78,11 @@ private:
|
||||
|
||||
std::set<ga::Offset> soloPoints_;
|
||||
|
||||
std::vector<ga::Offset> primStarts_;
|
||||
mutable std::vector<ga::Offset> primStarts_;
|
||||
mutable std::vector<ga::Offset> vertexPrims_;
|
||||
|
||||
mutable std::atomic<bool> primStartsDirty_{true};
|
||||
mutable tbb::spin_mutex primStartsMutex_;
|
||||
|
||||
// handles
|
||||
enzo::ga::AttributeHandleInt vertexCountHandlePrim_;
|
||||
|
||||
@@ -124,6 +124,12 @@ std::vector<std::weak_ptr<prm::Parameter>> nt::GeometryOperator::getParameters()
|
||||
return {parameters_.begin(), parameters_.end()};
|
||||
}
|
||||
|
||||
std::string nt::GeometryOperator::getLabel()
|
||||
{
|
||||
return getTypeName();
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::weak_ptr<const nt::GeometryConnection>> nt::GeometryOperator::getOutputConnections() const
|
||||
{
|
||||
return {outputConnections_.begin(), outputConnections_.end()};
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
std::vector<std::weak_ptr<prm::Parameter>> getParameters();
|
||||
std::weak_ptr<prm::Parameter> getParameter(std::string parameterName);
|
||||
|
||||
std::string getLabel(); // TODO: implement node labels
|
||||
std::string getTypeName();
|
||||
|
||||
void dirtyNode(bool dirtyDescendents=true);
|
||||
|
||||
161
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetMenuBar.cpp
Normal file
161
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetMenuBar.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetMenuBar.h"
|
||||
#include "Engine/Network/NetworkManager.h"
|
||||
#include "Engine/Operator/GeometryOperator.h"
|
||||
#include <QLabel>
|
||||
#include <qpainter.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <qwidget.h>
|
||||
#include <QButtonGroup>
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
#include <icecream.hpp>
|
||||
|
||||
GeoSheetModeButton::GeoSheetModeButton(QWidget* parent)
|
||||
: QPushButton(parent)
|
||||
{
|
||||
setFixedSize(QSize(23,23));
|
||||
setObjectName("GeoSheetModeButton");
|
||||
setCheckable(true);
|
||||
// setStyleSheet(
|
||||
// R"(
|
||||
// #GeoSheetModeButton
|
||||
// {
|
||||
// background: transparent;
|
||||
// border: none;
|
||||
// }
|
||||
// #GeoSheetModeButton::checked
|
||||
// {
|
||||
// opacity: 50;
|
||||
// border: none;
|
||||
// }
|
||||
// )");
|
||||
|
||||
}
|
||||
|
||||
void GeoSheetModeButton::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
hovered_=true;
|
||||
QPushButton::enterEvent(event);
|
||||
|
||||
}
|
||||
|
||||
void GeoSheetModeButton::leaveEvent(QEvent *event)
|
||||
{
|
||||
hovered_=false;
|
||||
QPushButton::leaveEvent(event);
|
||||
}
|
||||
|
||||
void GeoSheetModeButton::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
const QIcon buttonIcon = icon();
|
||||
|
||||
if(!buttonIcon.isNull())
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
QSize size = iconSize();
|
||||
|
||||
if(!isChecked())
|
||||
{
|
||||
painter.setOpacity(0.5);
|
||||
}
|
||||
if(hovered_)
|
||||
{
|
||||
size*=1.1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QPixmap pixmap = buttonIcon.pixmap(size);
|
||||
QPoint center = rect().center() - QPoint(size.width() / 2, size.height() / 2);
|
||||
painter.drawPixmap(center, pixmap);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
GeoSheetMenuBarModeSelection::GeoSheetMenuBarModeSelection(QWidget *parent, Qt::WindowFlags f)
|
||||
: QWidget(parent, f)
|
||||
{
|
||||
mainLayout_ = new QHBoxLayout();
|
||||
constexpr int mainMargin = 0;
|
||||
mainLayout_->setContentsMargins(mainMargin,mainMargin,mainMargin,mainMargin);
|
||||
|
||||
QWidget* buttonBg = new QWidget();
|
||||
buttonBg->setObjectName("GeoSheetMenuBarButtonBg");
|
||||
buttonBg->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
constexpr int bgSizeMargin = 5;
|
||||
buttonBg->setContentsMargins(bgSizeMargin,0,bgSizeMargin,0);
|
||||
buttonBg->setStyleSheet(
|
||||
R"(
|
||||
#GeoSheetMenuBarButtonBg
|
||||
{
|
||||
background-color: #242424;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
)");
|
||||
QHBoxLayout* buttonBgLayout = new QHBoxLayout();
|
||||
constexpr int margin = 0;
|
||||
buttonBgLayout->setContentsMargins(margin,margin,margin,margin);
|
||||
|
||||
modeButtonGroup_.setExclusive(true);
|
||||
|
||||
auto newButton = [this, &buttonBgLayout](const char* tooltip="", const char* iconPath=":/icons/attributePoint.svg")
|
||||
{
|
||||
auto newButton = new GeoSheetModeButton();
|
||||
newButton->setToolTip(tooltip);
|
||||
newButton->setIcon(QIcon(iconPath));
|
||||
modeButtonGroup_.addButton(newButton);
|
||||
buttonBgLayout->addWidget(newButton);
|
||||
return newButton;
|
||||
};
|
||||
|
||||
pointButton = newButton("Point Attributes", ":/icons/attributePoint.svg");
|
||||
vertexButton = newButton("Vertex Attributes", ":/icons/attributeVertex.svg");
|
||||
primitiveButton = newButton("Primitive Attributes", ":/icons/attributePrimitive.svg");
|
||||
globalButton = newButton("Global Attributes", ":/icons/attributeGlobal.svg");
|
||||
|
||||
pointButton->setChecked(true);
|
||||
|
||||
buttonBg->setLayout(buttonBgLayout);
|
||||
|
||||
mainLayout_->addWidget(buttonBg);
|
||||
|
||||
setLayout(mainLayout_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GeometrySpreadsheetMenuBar::GeometrySpreadsheetMenuBar(QWidget *parent, Qt::WindowFlags f)
|
||||
: QWidget(parent, f)
|
||||
{
|
||||
mainLayout_ = new QHBoxLayout();
|
||||
nodeLabel_ = new QLabel();
|
||||
modeSelection = new GeoSheetMenuBarModeSelection();
|
||||
|
||||
mainLayout_->addWidget(nodeLabel_);
|
||||
mainLayout_->addStretch();
|
||||
mainLayout_->addWidget(modeSelection);
|
||||
setProperty("class", "GeometrySpreadsheetMenuBar");
|
||||
setStyleSheet(
|
||||
R"(
|
||||
.GeometrySpreadsheetMenuBar,
|
||||
.GeometrySpreadsheetMenuBar *
|
||||
{
|
||||
background-color: #1B1B1B;
|
||||
}
|
||||
)");
|
||||
|
||||
constexpr int margins = 5;
|
||||
mainLayout_->setContentsMargins(margins, margins, margins, margins);
|
||||
|
||||
setLayout(mainLayout_);
|
||||
}
|
||||
|
||||
void GeometrySpreadsheetMenuBar::setNode(enzo::nt::OpId opId)
|
||||
{
|
||||
enzo::nt::GeometryOperator& geoOp = enzo::nt::nm().getGeoOperator(opId);
|
||||
nodeLabel_->setText("<b>Node: </b>" + QString::fromStdString(geoOp.getLabel()));
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Operator/OpInfo.h"
|
||||
#include "Engine/Types.h"
|
||||
#include <QWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <qbuttongroup.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <QLabel>
|
||||
|
||||
class GeoSheetModeButton
|
||||
: public QPushButton
|
||||
{
|
||||
public:
|
||||
GeoSheetModeButton(QWidget *parent = nullptr);
|
||||
private:
|
||||
QHBoxLayout* mainLayout_;
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
bool hovered_ = false;
|
||||
};
|
||||
|
||||
class GeoSheetMenuBarModeSelection
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
GeoSheetMenuBarModeSelection(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
|
||||
GeoSheetModeButton* pointButton;
|
||||
GeoSheetModeButton* vertexButton;
|
||||
GeoSheetModeButton* primitiveButton;
|
||||
GeoSheetModeButton* globalButton;
|
||||
private:
|
||||
QHBoxLayout* mainLayout_;
|
||||
QButtonGroup modeButtonGroup_;
|
||||
};
|
||||
|
||||
class GeometrySpreadsheetMenuBar
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
GeometrySpreadsheetMenuBar(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
GeoSheetMenuBarModeSelection* modeSelection;
|
||||
void setNode(enzo::nt::OpId opId);
|
||||
private:
|
||||
QHBoxLayout* mainLayout_;
|
||||
QLabel* nodeLabel_;
|
||||
};
|
||||
|
||||
249
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.cpp
Normal file
249
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.h"
|
||||
#include "Engine/Operator/Attribute.h"
|
||||
#include "Engine/Operator/AttributeHandle.h"
|
||||
#include "Engine/Operator/Geometry.h"
|
||||
#include "Engine/Types.h"
|
||||
#include <icecream.hpp>
|
||||
#include <memory>
|
||||
#include <qnamespace.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <QBrush>
|
||||
|
||||
|
||||
GeometrySpreadsheetModel::GeometrySpreadsheetModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GeometrySpreadsheetModel::geometryChanged(enzo::geo::Geometry& geometry)
|
||||
{
|
||||
beginResetModel();
|
||||
geometry_ = geometry;
|
||||
initBuffers();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void GeometrySpreadsheetModel::initBuffers()
|
||||
{
|
||||
// get sizes
|
||||
const auto attribCount = geometry_.getNumAttributes(attributeOwner_);
|
||||
|
||||
attribSizes_.clear();
|
||||
sectionAttribMap_.clear();
|
||||
attribSizes_.reserve(attribCount);
|
||||
|
||||
for(size_t i=0; i<attribCount; ++i)
|
||||
{
|
||||
if(auto attrib = geometry_.getAttributeByIndex(attributeOwner_, i).lock())
|
||||
{
|
||||
const auto size = attrib->getTypeSize();
|
||||
attribSizes_.push_back(size);
|
||||
|
||||
for(size_t j=0; j<size; ++j)
|
||||
{
|
||||
sectionAttribMap_.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GeometrySpreadsheetModel::setOwner(const enzo::ga::AttributeOwner owner)
|
||||
{
|
||||
beginResetModel();
|
||||
attributeOwner_ = owner;
|
||||
initBuffers();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int GeometrySpreadsheetModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
switch(attributeOwner_)
|
||||
{
|
||||
case enzo::ga::AttributeOwner::POINT:
|
||||
{
|
||||
return geometry_.getNumPoints();
|
||||
}
|
||||
case enzo::ga::AttributeOwner::VERTEX:
|
||||
{
|
||||
return geometry_.getNumVerts();
|
||||
}
|
||||
case enzo::ga::AttributeOwner::PRIMITIVE:
|
||||
{
|
||||
return geometry_.getNumPrims();
|
||||
}
|
||||
case enzo::ga::AttributeOwner::GLOBAL:
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GeometrySpreadsheetModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
|
||||
int columnCount = attributeColumnPadding_; // first column is for indices
|
||||
for(auto size : attribSizes_)
|
||||
{
|
||||
columnCount += size;
|
||||
}
|
||||
|
||||
return columnCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QVariant GeometrySpreadsheetModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// TODO: reimplement check
|
||||
// if (index.row() >= geometry_.getNumPoints())
|
||||
// {
|
||||
// return QVariant();
|
||||
// }
|
||||
|
||||
if(role == Qt::BackgroundRole && index.column()==0)
|
||||
{
|
||||
return QBrush("#1B1B1B");
|
||||
|
||||
}
|
||||
else if (role == Qt::DisplayRole)
|
||||
{
|
||||
|
||||
if(index.column()==0)
|
||||
{
|
||||
switch(attributeOwner_)
|
||||
{
|
||||
case enzo::ga::AttributeOwner::POINT:
|
||||
case enzo::ga::AttributeOwner::PRIMITIVE:
|
||||
{
|
||||
return index.row();
|
||||
}
|
||||
case enzo::ga::AttributeOwner::VERTEX:
|
||||
{
|
||||
const enzo::ga::Offset primOffset = geometry_.getVertexPrim(index.row());
|
||||
const enzo::ga::Offset startVert = geometry_.getPrimStartVertex(primOffset);
|
||||
const enzo::ga::Offset vertexNumber = index.row()-startVert;
|
||||
return QString::fromStdString(std::to_string(primOffset)+":"+std::to_string(vertexNumber));
|
||||
|
||||
}
|
||||
case enzo::ga::AttributeOwner::GLOBAL:
|
||||
{
|
||||
return "global";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
int attributeIndex = indexFromSection(index.column()-attributeColumnPadding_);
|
||||
if(std::shared_ptr<const enzo::ga::Attribute> attrib = geometry_.getAttributeByIndex(attributeOwner_, attributeIndex).lock())
|
||||
{
|
||||
const unsigned int valueIndex = index.column()-attributeIndex-attributeColumnPadding_;
|
||||
using namespace enzo::ga;
|
||||
|
||||
switch(attrib->getType())
|
||||
{
|
||||
case(AttributeType::intT):
|
||||
{
|
||||
const auto attribHandle = enzo::ga::AttributeHandleRO<enzo::bt::intT>(attrib);
|
||||
return static_cast<float>(attribHandle.getValue(index.row()));
|
||||
}
|
||||
case(AttributeType::floatT):
|
||||
{
|
||||
const auto attribHandle = enzo::ga::AttributeHandleRO<enzo::bt::floatT>(attrib);
|
||||
return attribHandle.getValue(index.row());
|
||||
}
|
||||
case(AttributeType::boolT):
|
||||
{
|
||||
const auto attribHandle = enzo::ga::AttributeHandleRO<enzo::bt::boolT>(attrib);
|
||||
return attribHandle.getValue(index.row()) ? "true" : "false";
|
||||
}
|
||||
case(AttributeType::vectorT):
|
||||
{
|
||||
const auto attribHandle = enzo::ga::AttributeHandleRO<enzo::bt::Vector3>(attrib);
|
||||
return attribHandle.getValue(index.row())[valueIndex];
|
||||
}
|
||||
default:
|
||||
{
|
||||
return "Failed";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Couldn't lock attribute");
|
||||
}
|
||||
// return geometry_.getPointPos(index.row()).x();
|
||||
}
|
||||
else
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
int GeometrySpreadsheetModel::indexFromSection(unsigned int section) const
|
||||
{
|
||||
if(section>=sectionAttribMap_.size())
|
||||
{
|
||||
throw std::out_of_range("Section is out of range of sectionAttributMap_, value: " + std::to_string(section) + " expected: <"+std::to_string(sectionAttribMap_.size()));
|
||||
}
|
||||
return sectionAttribMap_[section];
|
||||
}
|
||||
|
||||
|
||||
QVariant GeometrySpreadsheetModel::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
if(section==0) return "Index";
|
||||
auto attributeIndex = indexFromSection(section-attributeColumnPadding_);
|
||||
if(auto attrib = geometry_.getAttributeByIndex(attributeOwner_, attributeIndex).lock())
|
||||
{
|
||||
if(attribSizes_[attributeIndex]>1)
|
||||
{
|
||||
const unsigned int valueIndex = section-attributeIndex-attributeColumnPadding_;
|
||||
|
||||
std::string valueIndexString;
|
||||
if(attrib->getType()==enzo::ga::AttrType::vectorT)
|
||||
{
|
||||
valueIndexString = std::array{".x", ".y", ".z", ".w"}.at(valueIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
valueIndexString = "["+std::to_string(valueIndex)+"]";
|
||||
}
|
||||
|
||||
return QString::fromStdString(attrib->getName() + valueIndexString);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QString::fromStdString(attrib->getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("failed to lock attriubte index");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return QStringLiteral("Row %1").arg(section);
|
||||
}
|
||||
}
|
||||
35
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.h
Normal file
35
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "Engine/Types.h"
|
||||
#include "Engine/Operator/Geometry.h"
|
||||
|
||||
class GeometrySpreadsheetModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GeometrySpreadsheetModel(QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
int indexFromSection(unsigned int section) const;
|
||||
|
||||
void geometryChanged(enzo::geo::Geometry& geometry);
|
||||
void setOwner(const enzo::ga::AttributeOwner owner);
|
||||
void initBuffers();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
enzo::nt::OpId opId_;
|
||||
enzo::geo::Geometry geometry_;
|
||||
std::vector<unsigned int> attribSizes_;
|
||||
std::vector<unsigned int> sectionAttribMap_;
|
||||
const int attributeColumnPadding_ = 1;
|
||||
enzo::ga::AttributeOwner attributeOwner_=enzo::ga::AttributeOwner::POINT;
|
||||
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetPanel.h"
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetMenuBar.h"
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.h"
|
||||
#include "Engine/Network/NetworkManager.h"
|
||||
#include <QTableWidget>
|
||||
#include <QTreeWidget>
|
||||
#include <QLabel>
|
||||
#include <qframe.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <qtablewidget.h>
|
||||
#include <QPainterPath>
|
||||
|
||||
GeometrySpreadsheetPanel::GeometrySpreadsheetPanel(QWidget *parent, Qt::WindowFlags f)
|
||||
: QWidget(parent, f)
|
||||
{
|
||||
mainLayout_ = new QVBoxLayout();
|
||||
mainLayout_->setSpacing(0);
|
||||
|
||||
|
||||
view_ = new QTreeView(parent);
|
||||
view_->setRootIsDecorated(false);
|
||||
view_->setAlternatingRowColors(true);
|
||||
view_->setUniformRowHeights(true); // improves performance
|
||||
view_->setStyleSheet(R"(
|
||||
QTreeView {
|
||||
background-color: #282828;
|
||||
alternate-background-color: #242424;
|
||||
paint-alternating-row-colors-for-empty-area: 1;
|
||||
}
|
||||
QTreeView QScrollBar {
|
||||
background: #1B1B1B;
|
||||
width: 15px;
|
||||
}
|
||||
QTreeView QScrollBar::handle:vertical {
|
||||
background: #282828;
|
||||
min-height: 50px;
|
||||
border-radius: 5px;
|
||||
border-width: 1px;
|
||||
border-color: #2D2D2D;
|
||||
border-style: solid;
|
||||
margin:2px;
|
||||
}
|
||||
|
||||
QTreeView QScrollBar::add-page:vertical,
|
||||
QTreeView QScrollBar::sub-page:vertical,
|
||||
QTreeView QScrollBar::add-line:vertical,
|
||||
QTreeView QScrollBar::sub-line:vertical
|
||||
{ height: 0px; }
|
||||
|
||||
QHeaderView::section {
|
||||
background-color: #1B1B1B;
|
||||
}
|
||||
)");
|
||||
view_->setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
model_ = new GeometrySpreadsheetModel();
|
||||
view_->setModel(model_);
|
||||
|
||||
menuBar_ = new GeometrySpreadsheetMenuBar();
|
||||
// connect buttons
|
||||
connect(menuBar_->modeSelection->pointButton, &QPushButton::clicked, this, [this](){model_->setOwner(enzo::ga::AttributeOwner::POINT);});
|
||||
connect(menuBar_->modeSelection->vertexButton, &QPushButton::clicked, this, [this](){model_->setOwner(enzo::ga::AttributeOwner::VERTEX);});
|
||||
connect(menuBar_->modeSelection->primitiveButton, &QPushButton::clicked, this, [this](){model_->setOwner(enzo::ga::AttributeOwner::PRIMITIVE);});
|
||||
connect(menuBar_->modeSelection->globalButton, &QPushButton::clicked, this, [this](){model_->setOwner(enzo::ga::AttributeOwner::GLOBAL);});
|
||||
// set default
|
||||
menuBar_->modeSelection->pointButton->click();
|
||||
|
||||
|
||||
mainLayout_->addWidget(menuBar_);
|
||||
mainLayout_->addWidget(view_);
|
||||
|
||||
setLayout(mainLayout_);
|
||||
}
|
||||
|
||||
void GeometrySpreadsheetPanel::setNode(enzo::nt::OpId opId)
|
||||
{
|
||||
menuBar_->setNode(opId);
|
||||
}
|
||||
|
||||
|
||||
void GeometrySpreadsheetPanel::geometryChanged(enzo::geo::Geometry& geometry)
|
||||
{
|
||||
model_->geometryChanged(geometry);
|
||||
view_->update();
|
||||
}
|
||||
|
||||
void GeometrySpreadsheetPanel::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QPainterPath path;
|
||||
constexpr float radius = 10;
|
||||
path.addRoundedRect(mainLayout_->contentsRect(), radius, radius);
|
||||
QRegion region = QRegion(path.toFillPolygon().toPolygon());
|
||||
this->setMask(region);
|
||||
}
|
||||
|
||||
28
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetPanel.h
Normal file
28
src/Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetPanel.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <qtreeview.h>
|
||||
#include "Engine/Types.h"
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetModel.h"
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetMenuBar.h"
|
||||
|
||||
class GeometrySpreadsheetPanel
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
GeometrySpreadsheetPanel(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
public Q_SLOTS:
|
||||
void geometryChanged(enzo::geo::Geometry& geometry);
|
||||
void setNode(enzo::nt::OpId opId);
|
||||
private:
|
||||
QVBoxLayout* mainLayout_;
|
||||
QWidget* bgWidget_;
|
||||
GeometrySpreadsheetModel* model_;
|
||||
QTreeView* view_;
|
||||
GeometrySpreadsheetMenuBar* menuBar_;
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Gui/Interface.h"
|
||||
#include "Engine/Network/NetworkManager.h"
|
||||
#include "Engine/Operator/Geometry.h"
|
||||
#include "Gui/GeometrySpreadsheetPanel/GeometrySpreadsheetPanel.h"
|
||||
#include "Gui/ParametersPanel/ParametersPanel.h"
|
||||
#include "Gui/Viewport/Viewport.h"
|
||||
#include "Gui/Network/Network.h"
|
||||
@@ -8,6 +10,7 @@
|
||||
#include <qsplitter.h>
|
||||
#include <QTimer>
|
||||
#include <Gui/UtilWidgets/Splitter.h>
|
||||
#include <icecream.hpp>
|
||||
|
||||
EnzoUI::EnzoUI()
|
||||
{
|
||||
@@ -26,35 +29,41 @@ EnzoUI::EnzoUI()
|
||||
Viewport* viewport = new Viewport();
|
||||
Network* network = new Network();
|
||||
ParametersPanel* parametersPanel = new ParametersPanel();
|
||||
GeometrySpreadsheetPanel* geometrySpreadsheetPanel = new GeometrySpreadsheetPanel();
|
||||
|
||||
constexpr int margin = 2;
|
||||
viewport->layout()->setContentsMargins(margin, margin, margin, margin);
|
||||
network->layout()->setContentsMargins(margin, margin, margin, margin);
|
||||
parametersPanel->layout()->setContentsMargins(margin, margin, margin, margin);
|
||||
geometrySpreadsheetPanel->layout()->setContentsMargins(margin, margin, margin, margin);
|
||||
mainLayout_->setContentsMargins(margin, margin, margin, margin);
|
||||
|
||||
|
||||
|
||||
// TODO: dynamic splitters
|
||||
viewportSplitter_ = new Splitter(this);
|
||||
networkSplitter_ = new Splitter(this);
|
||||
spreadsheetSplitter_ = new Splitter(this);
|
||||
networkSplitter_->setOrientation(Qt::Vertical);
|
||||
spreadsheetSplitter_->setOrientation(Qt::Vertical);
|
||||
|
||||
spreadsheetSplitter_->addWidget(viewport);
|
||||
spreadsheetSplitter_->addWidget(geometrySpreadsheetPanel);
|
||||
spreadsheetSplitter_->setSizes({200,100});
|
||||
|
||||
|
||||
viewportSplitter_->addWidget(viewport);
|
||||
viewportSplitter_->addWidget(spreadsheetSplitter_);
|
||||
viewportSplitter_->addWidget(networkSplitter_);
|
||||
viewportSplitter_->setStretchFactor(0, 4);
|
||||
viewportSplitter_->setStretchFactor(1, 1);
|
||||
viewportSplitter_->setSizes({100,200});
|
||||
|
||||
networkSplitter_->addWidget(parametersPanel);
|
||||
networkSplitter_->addWidget(network);
|
||||
networkSplitter_->setStretchFactor(0, 10);
|
||||
networkSplitter_->setStretchFactor(1, 1);
|
||||
networkSplitter_->setSizes({40,100});
|
||||
|
||||
mainLayout_->addWidget(viewportSplitter_);
|
||||
|
||||
// connect signals
|
||||
connect(&enzo::nt::nm(), &enzo::nt::NetworkManager::updateDisplay, viewport, &Viewport::geometryChanged);
|
||||
enzo::nt::nm().displayNodeChanged.connect([parametersPanel](){parametersPanel->selectionChanged();});
|
||||
// connect(&enzo::nt::nm(), &enzo::nt::NetworkManager::updateDisplay, parametersPanel, &ParametersPanel::selectionChanged);
|
||||
enzo::nt::nm().displayNodeChanged.connect([parametersPanel](enzo::nt::OpId opId){parametersPanel->selectionChanged(opId);});
|
||||
enzo::nt::nm().displayNodeChanged.connect([geometrySpreadsheetPanel](enzo::nt::OpId opId){geometrySpreadsheetPanel->setNode(opId);});
|
||||
enzo::nt::nm().displayGeoChanged.connect([geometrySpreadsheetPanel](enzo::geo::Geometry& geometry){geometrySpreadsheetPanel->geometryChanged(geometry);});
|
||||
enzo::nt::nm().displayGeoChanged.connect([viewport](enzo::geo::Geometry& geometry){viewport->setGeometry(geometry);});
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class EnzoUI
|
||||
QVBoxLayout* viewportSplitLayout_;
|
||||
Splitter* viewportSplitter_;
|
||||
Splitter* networkSplitter_;
|
||||
Splitter* spreadsheetSplitter_;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -36,13 +36,11 @@ ParametersPanel::ParametersPanel(QWidget *parent, Qt::WindowFlags f)
|
||||
setLayout(mainLayout_);
|
||||
}
|
||||
|
||||
void ParametersPanel::selectionChanged()
|
||||
void ParametersPanel::selectionChanged(enzo::nt::OpId opId)
|
||||
{
|
||||
using namespace enzo;
|
||||
enzo::nt::NetworkManager& nm = enzo::nt::nm();
|
||||
std::optional<enzo::nt::OpId> displayOpId = nm.getDisplayOp();
|
||||
|
||||
if(!displayOpId.has_value()) return;
|
||||
const enzo::nt::OpId displayOpId = opId;
|
||||
|
||||
// clear layout safely
|
||||
QLayoutItem *child;
|
||||
@@ -51,7 +49,7 @@ void ParametersPanel::selectionChanged()
|
||||
delete child;
|
||||
}
|
||||
|
||||
enzo::nt::GeometryOperator& displayOp = nm.getGeoOperator(displayOpId.value());
|
||||
enzo::nt::GeometryOperator& displayOp = nm.getGeoOperator(displayOpId);
|
||||
auto parameters = displayOp.getParameters();
|
||||
|
||||
std::vector<enzo::ui::AbstractFormParm*> parameterWidgets;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include "Engine/Types.h"
|
||||
|
||||
class ParametersPanel
|
||||
: public QWidget
|
||||
@@ -9,7 +10,7 @@ class ParametersPanel
|
||||
public:
|
||||
ParametersPanel(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
public Q_SLOTS:
|
||||
void selectionChanged();
|
||||
void selectionChanged(enzo::nt::OpId opId);
|
||||
private:
|
||||
QVBoxLayout* mainLayout_;
|
||||
QVBoxLayout* parametersLayout_;
|
||||
|
||||
@@ -20,7 +20,7 @@ Viewport::Viewport(QWidget *parent, Qt::WindowFlags f)
|
||||
this->setLayout(mainLayout_);
|
||||
}
|
||||
|
||||
void Viewport::geometryChanged(enzo::geo::Geometry& geometry)
|
||||
void Viewport::setGeometry(enzo::geo::Geometry& geometry)
|
||||
{
|
||||
openGLWidget_->geometryChanged(geometry);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ class Viewport
|
||||
{
|
||||
public:
|
||||
Viewport(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
void setGeometry(enzo::geo::Geometry& geometry);
|
||||
private:
|
||||
QVBoxLayout* mainLayout_;
|
||||
ViewportGLWidget* openGLWidget_;
|
||||
@@ -23,6 +24,4 @@ private:
|
||||
QPointF leftStartPos_;
|
||||
bool rightMouseDown_=false;
|
||||
QPointF rightStartPos_;
|
||||
public Q_SLOTS:
|
||||
void geometryChanged(enzo::geo::Geometry& geometry);
|
||||
};
|
||||
|
||||
76
static/icons/attributeBase.svg
Normal file
76
static/icons/attributeBase.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 18 KiB |
76
static/icons/attributeGlobal.svg
Normal file
76
static/icons/attributeGlobal.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 18 KiB |
81
static/icons/attributePoint.svg
Normal file
81
static/icons/attributePoint.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 18 KiB |
76
static/icons/attributePrimitive.svg
Normal file
76
static/icons/attributePrimitive.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 18 KiB |
121
static/icons/attributeVertex.svg
Normal file
121
static/icons/attributeVertex.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
@@ -1,5 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>node-icons/grid.svg</file>
|
||||
<file>icons/attributePoint.svg</file>
|
||||
<file>icons/attributeVertex.svg</file>
|
||||
<file>icons/attributePrimitive.svg</file>
|
||||
<file>icons/attributeGlobal.svg</file>
|
||||
<file>icons/attributeBase.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
Reference in New Issue
Block a user