#include "QskLevelingSensorSkinlet.h" #include "QskLevelingSensor.h" #include "QskLevelingSensorUtility.h" #include "QskLevelingSensorNodes.h" #include "QsgNodeUtility.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using Q = LevelingSensor; using R = LevelingSensorSkinlet::NodeRole; using namespace qsg; float LevelingSensorSkinlet::radius2(const QskSkinnable* const skinnable) { // outer radius const auto* const sensor = static_cast(skinnable); const auto contentsRect = sensor->contentsRect(); return 0.5f * qMin(contentsRect.width(), contentsRect.height()); } float LevelingSensorSkinlet::radius1(const QskSkinnable* const skinnable) { const auto scale = skinnable->strutSizeHint(Q::Horizon); return radius2(skinnable) * scale.width(); } QPointF LevelingSensorSkinlet::center(const QskSkinnable* const skinnable) { const auto* const sensor = static_cast(skinnable); return sensor->contentsRect().center(); } LevelingSensorSkinlet::LevelingSensorSkinlet(QskSkin* skin) : Inherited(skin) { setNodeRoles({ OuterDisk, Horizon, HorizonClip, TickmarksX, TickmarksXLabels, TickmarksY, TickmarksYLabels, TickmarksZ, TickmarksZLabels, }); } template Q_REQUIRED_RESULT QRectF LevelingSensorSkinlet::subControlRect(const LevelingSensor* const sensor, const QRectF& contentsRect) const = delete; template<> Q_REQUIRED_RESULT QRectF LevelingSensorSkinlet::subControlRect(const LevelingSensor* const sensor, const QRectF& contentsRect) const { const auto radius = radius2(sensor); const auto scale = sensor->strutSizeHint(Q::OuterDisk); const auto width = 2 * radius * scale.width(); const auto height = width; const auto x = contentsRect.center().x() - width / 2; const auto y = contentsRect.center().y() - height / 2; return { x, y, width, height }; } template<> Q_REQUIRED_RESULT QRectF LevelingSensorSkinlet::subControlRect(const LevelingSensor* const sensor, const QRectF& contentsRect) const { const auto scale = sensor->strutSizeHint(Q::Horizon); const auto width = 2 * radius1(sensor) * scale.width(); const auto height = width; return { center(sensor).x() - width / 2, center(sensor).y() - height / 2, width, height }; } QRectF LevelingSensorSkinlet::subControlRect(const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl) const { const auto* const sensor = static_cast(skinnable); if (subControl == Q::OuterDisk) { return subControlRect(sensor, contentsRect); } if (subControl == Q::Horizon) { return subControlRect(sensor, contentsRect); } return Inherited::subControlRect(skinnable, contentsRect, subControl); } template QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const = delete; template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::OuterDisk; const auto contentsRect = sensor->contentsRect(); const auto boxRect = subControlRect(sensor, contentsRect); const auto boxShapeMetrics = QskBoxShapeMetrics{ boxRect.width() / 2 }; const auto boxBorderMetrics = sensor->boxBorderMetricsHint(subControl); const auto boxBorderColors = sensor->boxBorderColorsHint(subControl); const auto boxGradient = sensor->gradientHint(subControl); auto* const root = ensure>::node(node); auto* const bNode = static_cast(root->firstChild()); const auto size = radius2(sensor) * sensor->strutSizeHint(Q::OuterDisk).width(); updateBoxNode(sensor, bNode, { 0, 0, 2 * size, 2 * size }, boxShapeMetrics, boxBorderMetrics, boxBorderColors, boxGradient); const auto cX = center(sensor).x(); const auto cY = center(sensor).y(); const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); const auto matrix = matrix_deg(0.0, 0.0, 0.0, cX, cY, 0) * matrix_deg(0.0, 0.0, rZ, 0, 0, 0) * matrix_deg(0.0, 0.0, 0.0, -size, -size, 0); root->setMatrix(matrix); return root; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::Horizon; const auto r1 = radius1(sensor); const auto cX = center(sensor).x(); const auto cY = center(sensor).y(); const auto rX = sensor->rotation().x(); const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); const auto dY = 2 * sensor->angle().y(); const auto p = qBound(0.0, 0.5 + (-rX / dY), 1.0); const auto shape = QskBoxShapeMetrics{ r1 }; const auto bmetrics = sensor->boxBorderMetricsHint(subControl); const auto bcolors = sensor->boxBorderColorsHint(subControl); auto gradient = sensor->gradientHint(Q::Horizon); gradient.setDirection(QskGradient::Linear); gradient.setLinearDirection(Qt::Vertical); gradient.setStops({ {0.0, gradient.startColor()}, {p, gradient.startColor()}, {p, gradient.endColor()}, {1.0, gradient.endColor()} }); auto* const tNode = ensure>::node(node); auto* const boxNode = static_cast(tNode->firstChild()); updateBoxNode(sensor, boxNode, { 0, 0, 2 * r1, 2 * r1 }, shape, bmetrics, bcolors, gradient); const auto matrix = matrix_deg(0, 0, 0, cX, cY, 0) * matrix_deg(0, 0, rZ, 0, 0, 0) * matrix_deg(0, 0, 0, -r1, -r1, 0); tNode->setMatrix(matrix); return tNode; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::TickmarksX; const auto color = sensor->color(subControl); const auto scale = sensor->strutSizeHint(subControl); const auto cX = center(sensor).x(); const auto cY = center(sensor).y(); const auto rX = sensor->rotation().x(); const auto rY = sensor->rotation().y(); const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); const auto r1 = radius1(sensor); const auto r3 = r1 * scale.height(); const auto sX = r1 / sensor->angle().x(); const auto sY = r1 / sensor->angle().y(); const auto tX = static_cast(rY * sX); const auto tY = 0.0; // static_cast(rX * sY); auto* const clipping = ensure>>::node(node); auto* const transform = static_cast(clipping->firstChild()); auto* const tickmarks = static_cast(transform->firstChild()); auto size = qvariant_cast(sensor->effectiveSkinHint(subControl)) * r3; clipping->setGeometryProperties(r1, cX, cY); tickmarks->setMaterialProperties(color); tickmarks->setGeometryProperties(sensor->tickmarks(Qt::XAxis), size, {sX, 0.0f}, {tX, tY}); const auto matrix = matrix_deg(0, 0, rZ, cX, cY, 0); transform->setMatrix(matrix); return clipping; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::TickmarksY; const auto color = sensor->color(subControl); const auto scale = sensor->strutSizeHint(subControl); const auto r1 = radius1(sensor); const auto r3 = r1 * scale.width(); const auto rX = 0.00; const auto rY = 0.00; const auto rZ = sensor->rotation().z(); const auto tX = center(sensor).x(); const auto tY = center(sensor).y(); const auto tZ = 0.0; auto* const cNode = ensure>>::node(node); auto* const tNode = static_cast(cNode->firstChild()); auto* const lNode = static_cast(tNode->firstChild()); auto size = qvariant_cast(sensor->effectiveSkinHint(subControl)) * r3; cNode->setGeometryProperties(r1, tX, tY); const auto sY = static_cast(r1 / sensor->angle().y()); lNode->setMaterialProperties(color); #ifdef USE_FILTERING using TickType = QskScaleTickmarks::TickType; const auto filter = [=](TickType, qreal v){ return rY - r1 / sY <= v && v <= rY + r1 / sY; }; lNode->setGeometryProperties(filtered(sensor->tickmarks(Qt::YAxis), filter), size, {0.0f, sY}, {}, 1.0f, true); #else lNode->setGeometryProperties(sensor->tickmarks(Qt::YAxis), size, {0.0f, sY}); #endif const auto matrix = matrix_deg(rX, rY, rZ, tX, tY, tZ); tNode->setMatrix(matrix); return cNode; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::TickmarksZ; const auto color = sensor->color(subControl); const auto scale = sensor->strutSizeHint(subControl); const auto r1 = radius1(sensor); const auto r2 = radius2(sensor); const auto r3 = qvariant_cast(sensor->effectiveSkinHint(subControl)) * (r2 - r1) + QVector3D{r1, r1, r1}; auto* const transform = ensure>::node(node); auto* const tickmarksNode = static_cast(transform->firstChild()); tickmarksNode->setMaterialProperties(color); tickmarksNode->setGeometryProperties(sensor->tickmarks(Qt::ZAxis), r1, r3); const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); const auto tX = center(sensor).x(); const auto tY = center(sensor).y(); const auto matrix = matrix_deg(0.0, 0.0, rZ, tX, tY); transform->setMatrix(matrix); return transform; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::TickmarksXLabels; const auto r1 = radius1(sensor); const auto r3 = static_cast(r1 * sensor->strutSizeHint(Q::TickmarksX).height()); const auto sX = r1 / sensor->angle().x(); const auto sY = r1 / sensor->angle().y(); const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); const auto cX = center(sensor).x(); const auto cY = center(sensor).y(); const auto tX = sensor->rotation().y() * sX; const auto tY = r3; auto* const cNode = ensure>>::node(node); auto* const tNode = static_cast(cNode->firstChild()); auto* const lNode = static_cast(tNode->firstChild()); tNode->setMatrix(matrix_deg(0.0, 0.0, rZ, cX, cY)); cNode->setGeometryProperties(r1, center(sensor).x(), center(sensor).y()); lNode->update(sensor, subControl, sensor->tickmarkLabels(Qt::XAxis), { sX , 0.0}, {tX, tY}); return cNode; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::TickmarksYLabels; const auto r1 = radius1(sensor); const auto r3 = static_cast(r1 * sensor->strutSizeHint(Q::TickmarksY).width()); const auto cX = static_cast(center(sensor).x()); const auto cY = static_cast(center(sensor).y()); const auto rZ = sensor->rotation().z(); auto* const cNode = ensure>>::node(node); auto* const tNode = static_cast(cNode->firstChild()); auto* const lNode = static_cast(tNode->firstChild()); cNode->setGeometryProperties(r1, cX, cY); tNode->setMatrix(matrix_deg(0.0, 0.0, 0, cX, cY)); lNode->update(sensor, subControl, sensor->tickmarkLabels(Qt::YAxis), { 0.0, r1 / sensor->angle().y() }, {r3, 0.0}); return cNode; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto subControl = Q::TickmarksZLabels; auto* const tNode = ensure>::node(node); auto* const lNode = static_cast(tNode->firstChild()); const auto r1 = radius1(sensor); const auto r3 = static_cast(r1 * sensor->strutSizeHint(subControl).width()); const auto cX = static_cast(center(sensor).x()); const auto cY = static_cast(center(sensor).y()); const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); lNode->update(sensor, subControl, sensor->tickmarkLabels(Qt::ZAxis), { r3, r3 }); tNode->setMatrix(matrix_deg(0.0, 0.0, rZ, cX, cY)); return tNode; } template<> QSGNode* LevelingSensorSkinlet::updateSubNode(const LevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node) const { const auto cX = center(sensor).x(); const auto cY = center(sensor).y(); const auto r1 = radius1(sensor); auto* const clipNode = ensure::node(node); clipNode->setGeometryProperties(r1, cX, cY); return clipNode; } QSGNode* LevelingSensorSkinlet::updateSubNode( const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node) const { const auto* const sensor = static_cast(skinnable); const auto subControl = [nodeRole, sensor](){ switch(static_cast(nodeRole)) { case OuterDisk: return Q::OuterDisk; case Horizon: return Q::Horizon; case HorizonClip: return Q::Horizon; case TickmarksX: return Q::TickmarksX; case TickmarksXLabels: return Q::TickmarksXLabels; case TickmarksY: return Q::TickmarksY; case TickmarksYLabels: return Q::TickmarksYLabels; case TickmarksZ: return Q::TickmarksZ; case TickmarksZLabels: return Q::TickmarksZLabels; default: return QskAspect::NoSubcontrol; } }(); if (qvariant_cast(sensor->effectiveSkinHint(subControl | QskAspect::Option))) { return nullptr; } switch(static_cast(nodeRole)) { case OuterDisk: return updateSubNode(sensor, nodeRole, node); case Horizon: return updateSubNode(sensor, nodeRole, node); case HorizonClip: return updateSubNode(sensor, nodeRole, node); case TickmarksX: return updateSubNode(sensor, nodeRole, node); case TickmarksXLabels: return updateSubNode(sensor, nodeRole, node); case TickmarksY: return updateSubNode(sensor, nodeRole, node); case TickmarksYLabels: return updateSubNode(sensor, nodeRole, node); case TickmarksZ: return updateSubNode(sensor, nodeRole, node); case TickmarksZLabels: return updateSubNode(sensor, nodeRole, node); default: return Inherited::updateSubNode(sensor, nodeRole, node); } } #include "moc_QskLevelingSensorSkinlet.cpp"