feat: Add animated home button to view cube to reset camera

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-17 16:56:25 -07:00
parent 405e151f12
commit c28c080009
5 changed files with 122 additions and 4 deletions

View File

@@ -269,6 +269,70 @@ void Camera::animateToPlaneView(int plane)
animGroup->start(QAbstractAnimation::DeleteWhenStopped); animGroup->start(QAbstractAnimation::DeleteWhenStopped);
} }
void Camera::animateToHomeView()
{
auto* animGroup = new QParallelAnimationGroup(this);
const float full_circle = 360.0f * 16.0f;
float currentXRot = xRotation();
float targetXRot = 30 * 16;
float diffX = targetXRot - currentXRot;
diffX = fmod(diffX, full_circle);
if (diffX > full_circle / 2.0f) {
diffX -= full_circle;
} else if (diffX < -full_circle / 2.0f) {
diffX += full_circle;
}
auto* xRotAnim = new QPropertyAnimation(this, "xRotation");
xRotAnim->setDuration(300);
xRotAnim->setStartValue(currentXRot);
xRotAnim->setEndValue(currentXRot + diffX);
xRotAnim->setEasingCurve(QEasingCurve::InOutQuad);
animGroup->addAnimation(xRotAnim);
float currentYRot = yRotation();
float targetYRot = -45 * 16;
float diffY = targetYRot - currentYRot;
diffY = fmod(diffY, full_circle);
if (diffY > full_circle / 2.0f) {
diffY -= full_circle;
} else if (diffY < -full_circle / 2.0f) {
diffY += full_circle;
}
auto* yRotAnim = new QPropertyAnimation(this, "yRotation");
yRotAnim->setDuration(300);
yRotAnim->setStartValue(currentYRot);
yRotAnim->setEndValue(currentYRot + diffY);
yRotAnim->setEasingCurve(QEasingCurve::InOutQuad);
animGroup->addAnimation(yRotAnim);
auto* panXAnim = new QPropertyAnimation(this, "panX");
panXAnim->setDuration(300);
panXAnim->setStartValue(panX());
panXAnim->setEndValue(0.0f);
panXAnim->setEasingCurve(QEasingCurve::InOutQuad);
animGroup->addAnimation(panXAnim);
auto* panYAnim = new QPropertyAnimation(this, "panY");
panYAnim->setDuration(300);
panYAnim->setStartValue(panY());
panYAnim->setEndValue(0.0f);
panYAnim->setEasingCurve(QEasingCurve::InOutQuad);
animGroup->addAnimation(panYAnim);
auto* zoomAnim = new QPropertyAnimation(this, "zoom");
zoomAnim->setDuration(300);
zoomAnim->setStartValue(zoom());
zoomAnim->setEndValue(-20.0f);
zoomAnim->setEasingCurve(QEasingCurve::InOutQuad);
animGroup->addAnimation(zoomAnim);
animGroup->start(QAbstractAnimation::DeleteWhenStopped);
}
void Camera::startRotation(const QVector3D& pivot) void Camera::startRotation(const QVector3D& pivot)
{ {
m_rotationPivot = pivot; m_rotationPivot = pivot;

View File

@@ -41,6 +41,7 @@ public:
void animateToPlaneView(int plane); void animateToPlaneView(int plane);
void animateRestoreState(); void animateRestoreState();
void animateToHomeView();
void startRotation(const QVector3D& pivot); void startRotation(const QVector3D& pivot);
void stopRotation(); void stopRotation();

View File

@@ -5,10 +5,12 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLTexture> #include <QOpenGLTexture>
#include <QScreen> #include <QScreen>
#include <QSvgRenderer>
#include <QVector> #include <QVector>
ViewCube::ViewCube() ViewCube::ViewCube()
{ {
m_homeButtonRenderer = new QSvgRenderer(QString(":/icons/rectangle.svg"));
for (int i = 0; i < 6; ++i) { for (int i = 0; i < 6; ++i) {
m_faceTextures[i] = nullptr; m_faceTextures[i] = nullptr;
} }
@@ -20,6 +22,7 @@ ViewCube::~ViewCube()
delete m_faceTextures[i]; delete m_faceTextures[i];
} }
delete m_textureShaderProgram; delete m_textureShaderProgram;
delete m_homeButtonRenderer;
m_cubeVbo.destroy(); m_cubeVbo.destroy();
m_cubeVao.destroy(); m_cubeVao.destroy();
m_axesVbo.destroy(); m_axesVbo.destroy();
@@ -42,10 +45,9 @@ void ViewCube::paintGL(QOpenGLShaderProgram* simpleShader, int simpleShaderColor
QRect viewCubeRect(width - viewCubeSize, 0, viewCubeSize, viewCubeSize); QRect viewCubeRect(width - viewCubeSize, 0, viewCubeSize, viewCubeSize);
QPoint physicalMousePos = mousePos * QGuiApplication::primaryScreen()->devicePixelRatio(); QPoint physicalMousePos = mousePos * QGuiApplication::primaryScreen()->devicePixelRatio();
float opacity = 0.5f; m_isHovered = viewCubeRect.contains(physicalMousePos);
if (viewCubeRect.contains(physicalMousePos)) {
opacity = 1.0f; float opacity = m_isHovered ? 1.0f : 0.5f;
}
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -210,3 +212,39 @@ void ViewCube::drawAxes(QOpenGLShaderProgram* simpleShader, int colorLoc, const
glLineWidth(1.0f); glLineWidth(1.0f);
} }
void ViewCube::paint2D(QPainter& painter, int widgetWidth, int widgetHeight)
{
if (!m_isHovered) {
return;
}
int viewCubeSize = 150; // logical pixels
int buttonSize = 24;
int buttonMargin = 8;
int viewCubeX = widgetWidth - viewCubeSize;
int viewCubeY = 0;
m_homeButtonRect = QRect(viewCubeX - buttonMargin - buttonSize, viewCubeY, buttonSize, buttonSize);
if (m_homeButtonRenderer && m_homeButtonRenderer->isValid()) {
m_homeButtonRenderer->render(&painter, m_homeButtonRect);
}
}
bool ViewCube::handleMousePress(const QPoint& pos, int widgetWidth, int widgetHeight)
{
if (!m_isHovered) {
return false;
}
int viewCubeSize = 150;
int buttonSize = 24;
int buttonMargin = 8;
int viewCubeX = widgetWidth - viewCubeSize;
int viewCubeY = 0;
QRect homeButtonRect(viewCubeX - buttonMargin - buttonSize, viewCubeY, buttonSize, buttonSize);
return homeButtonRect.contains(pos);
}

View File

@@ -9,6 +9,8 @@
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
class QOpenGLTexture; class QOpenGLTexture;
class QPainter;
class QSvgRenderer;
class ViewCube : protected QOpenGLFunctions class ViewCube : protected QOpenGLFunctions
{ {
@@ -18,6 +20,8 @@ public:
void initializeGL(); void initializeGL();
void paintGL(QOpenGLShaderProgram* simpleShader, int simpleShaderColorLoc, const QMatrix4x4& viewMatrix, int width, int height, const QPoint& mousePos); void paintGL(QOpenGLShaderProgram* simpleShader, int simpleShaderColorLoc, const QMatrix4x4& viewMatrix, int width, int height, const QPoint& mousePos);
void paint2D(QPainter& painter, int widgetWidth, int widgetHeight);
bool handleMousePress(const QPoint& pos, int widgetWidth, int widgetHeight);
private: private:
void createFaceTextures(); void createFaceTextures();
@@ -26,6 +30,10 @@ private:
void drawViewCube(const QMatrix4x4& projection, const QMatrix4x4& view, float opacity); void drawViewCube(const QMatrix4x4& projection, const QMatrix4x4& view, float opacity);
void drawAxes(QOpenGLShaderProgram* simpleShader, int colorLoc, const QMatrix4x4& projection, const QMatrix4x4& view); void drawAxes(QOpenGLShaderProgram* simpleShader, int colorLoc, const QMatrix4x4& projection, const QMatrix4x4& view);
bool m_isHovered = false;
QRect m_homeButtonRect;
QSvgRenderer* m_homeButtonRenderer = nullptr;
QOpenGLTexture* m_faceTextures[6]; QOpenGLTexture* m_faceTextures[6];
QOpenGLShaderProgram* m_textureShaderProgram = nullptr; QOpenGLShaderProgram* m_textureShaderProgram = nullptr;

View File

@@ -202,6 +202,7 @@ void ViewportWidget::paintGL()
m_sketchGrid->paintAxisLabels(painter, static_cast<SketchGrid::SketchPlane>(m_currentPlane), model, projection); m_sketchGrid->paintAxisLabels(painter, static_cast<SketchGrid::SketchPlane>(m_currentPlane), model, projection);
} }
m_featureBrowser->paint(painter, width(), height()); m_featureBrowser->paint(painter, width(), height());
m_viewCube->paint2D(painter, width(), height());
if (m_activeSketchTool) { if (m_activeSketchTool) {
@@ -230,6 +231,12 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event)
} }
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
if (m_viewCube->handleMousePress(event->pos(), width(), height())) {
m_camera->animateToHomeView();
update();
return;
}
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
if (m_highlightedPlane != SketchPlane::NONE) { if (m_highlightedPlane != SketchPlane::NONE) {
emit planeSelected(m_highlightedPlane); emit planeSelected(m_highlightedPlane);