feat: Implement floating feature browser in viewport with transparent background
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include "SketchFeature.h"
|
#include "SketchFeature.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@@ -26,9 +27,28 @@ void Document::clear()
|
|||||||
{
|
{
|
||||||
qDeleteAll(m_features);
|
qDeleteAll(m_features);
|
||||||
m_features.clear();
|
m_features.clear();
|
||||||
|
m_fileName.clear();
|
||||||
emit cleared();
|
emit cleared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QList<Feature*>& Document::features() const
|
||||||
|
{
|
||||||
|
return m_features;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::setFileName(const QString& fileName)
|
||||||
|
{
|
||||||
|
m_fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Document::fileName() const
|
||||||
|
{
|
||||||
|
if (m_fileName.isEmpty()) {
|
||||||
|
return "Untitled";
|
||||||
|
}
|
||||||
|
return QFileInfo(m_fileName).fileName();
|
||||||
|
}
|
||||||
|
|
||||||
bool Document::save(const QString& path) const
|
bool Document::save(const QString& path) const
|
||||||
{
|
{
|
||||||
QJsonArray featuresArray;
|
QJsonArray featuresArray;
|
||||||
|
|||||||
@@ -19,12 +19,17 @@ public:
|
|||||||
bool save(const QString& path) const;
|
bool save(const QString& path) const;
|
||||||
bool load(const QString& path);
|
bool load(const QString& path);
|
||||||
|
|
||||||
|
const QList<Feature*>& features() const;
|
||||||
|
void setFileName(const QString& fileName);
|
||||||
|
QString fileName() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void featureAdded(Feature* feature);
|
void featureAdded(Feature* feature);
|
||||||
void cleared();
|
void cleared();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Feature*> m_features;
|
QList<Feature*> m_features;
|
||||||
|
QString m_fileName;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DOCUMENT_H
|
#endif // DOCUMENT_H
|
||||||
|
|||||||
@@ -8,9 +8,6 @@
|
|||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QDockWidget>
|
|
||||||
#include <QTreeWidget>
|
|
||||||
#include <QTreeWidgetItem>
|
|
||||||
#include <QToolBar>
|
#include <QToolBar>
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -84,17 +81,9 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
setCentralWidget(m_viewport);
|
setCentralWidget(m_viewport);
|
||||||
|
|
||||||
m_document = new Document(this);
|
m_document = new Document(this);
|
||||||
connect(m_document, &Document::featureAdded, this, &MainWindow::onFeatureAdded);
|
m_viewport->setDocument(m_document);
|
||||||
connect(m_document, &Document::cleared, this, &MainWindow::onDocumentCleared);
|
connect(m_document, &Document::featureAdded, m_viewport, QOverload<>::of(&QWidget::update));
|
||||||
|
connect(m_document, &Document::cleared, m_viewport, QOverload<>::of(&QWidget::update));
|
||||||
QDockWidget *dock = new QDockWidget("Browser", this);
|
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, dock);
|
|
||||||
|
|
||||||
m_featureTree = new QTreeWidget(dock);
|
|
||||||
m_featureTree->setHeaderHidden(true);
|
|
||||||
dock->setWidget(m_featureTree);
|
|
||||||
|
|
||||||
m_rootItem = new QTreeWidgetItem(m_featureTree);
|
|
||||||
|
|
||||||
setCurrentFile(QString());
|
setCurrentFile(QString());
|
||||||
}
|
}
|
||||||
@@ -173,26 +162,11 @@ bool MainWindow::saveAs()
|
|||||||
void MainWindow::setCurrentFile(const QString &fileName)
|
void MainWindow::setCurrentFile(const QString &fileName)
|
||||||
{
|
{
|
||||||
m_currentFile = fileName;
|
m_currentFile = fileName;
|
||||||
|
m_document->setFileName(fileName);
|
||||||
setWindowFilePath(m_currentFile);
|
setWindowFilePath(m_currentFile);
|
||||||
|
|
||||||
QString shownName = m_currentFile;
|
QString shownName = m_currentFile;
|
||||||
if (m_currentFile.isEmpty())
|
if (m_currentFile.isEmpty())
|
||||||
shownName = "Untitled";
|
shownName = "Untitled";
|
||||||
setWindowTitle(tr("%1[*] - %2").arg(QFileInfo(shownName).fileName(), tr("OpenCAD")));
|
setWindowTitle(tr("%1[*] - %2").arg(QFileInfo(shownName).fileName(), tr("OpenCAD")));
|
||||||
|
|
||||||
if (m_rootItem) {
|
|
||||||
m_rootItem->setText(0, QFileInfo(shownName).fileName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::onFeatureAdded(Feature* feature)
|
|
||||||
{
|
|
||||||
QTreeWidgetItem *item = new QTreeWidgetItem(m_rootItem);
|
|
||||||
item->setText(0, feature->name());
|
|
||||||
m_rootItem->setExpanded(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::onDocumentCleared()
|
|
||||||
{
|
|
||||||
qDeleteAll(m_rootItem->takeChildren());
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
class ViewportWidget;
|
class ViewportWidget;
|
||||||
class Document;
|
class Document;
|
||||||
class Feature;
|
class Feature;
|
||||||
class QTreeWidget;
|
|
||||||
class QTreeWidgetItem;
|
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
@@ -23,18 +21,12 @@ private slots:
|
|||||||
bool saveAs();
|
bool saveAs();
|
||||||
void createSketch();
|
void createSketch();
|
||||||
|
|
||||||
void onFeatureAdded(Feature* feature);
|
|
||||||
void onDocumentCleared();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setCurrentFile(const QString &fileName);
|
void setCurrentFile(const QString &fileName);
|
||||||
|
|
||||||
ViewportWidget *m_viewport;
|
ViewportWidget *m_viewport;
|
||||||
Document *m_document;
|
Document *m_document;
|
||||||
QString m_currentFile;
|
QString m_currentFile;
|
||||||
|
|
||||||
QTreeWidget* m_featureTree;
|
|
||||||
QTreeWidgetItem* m_rootItem;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#include "ViewportWidget.h"
|
#include "ViewportWidget.h"
|
||||||
#include "ViewCube.h"
|
#include "ViewCube.h"
|
||||||
#include "SketchGrid.h"
|
#include "SketchGrid.h"
|
||||||
|
#include "Document.h"
|
||||||
|
#include "Feature.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -21,6 +24,11 @@ ViewportWidget::~ViewportWidget()
|
|||||||
delete m_sketchGrid;
|
delete m_sketchGrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewportWidget::setDocument(Document* document)
|
||||||
|
{
|
||||||
|
m_document = document;
|
||||||
|
}
|
||||||
|
|
||||||
void ViewportWidget::initializeGL()
|
void ViewportWidget::initializeGL()
|
||||||
{
|
{
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
@@ -61,11 +69,12 @@ void ViewportWidget::paintGL()
|
|||||||
|
|
||||||
glViewport(0, 0, width(), height());
|
glViewport(0, 0, width(), height());
|
||||||
|
|
||||||
if (m_currentPlane != SketchPlane::NONE) {
|
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
if (m_currentPlane != SketchPlane::NONE) {
|
||||||
drawAxisLabels(painter, model, projection);
|
drawAxisLabels(painter, model, projection);
|
||||||
painter.end();
|
|
||||||
}
|
}
|
||||||
|
drawFeatureBrowser(painter);
|
||||||
|
painter.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportWidget::resizeGL(int w, int h)
|
void ViewportWidget::resizeGL(int w, int h)
|
||||||
@@ -181,3 +190,50 @@ void ViewportWidget::drawAxisLabels(QPainter& painter, const QMatrix4x4& modelVi
|
|||||||
drawLabelsForAxis(2); // Z
|
drawLabelsForAxis(2); // Z
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewportWidget::drawFeatureBrowser(QPainter& painter)
|
||||||
|
{
|
||||||
|
if (!m_document) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter.setFont(QFont("Arial", 10));
|
||||||
|
|
||||||
|
const int padding = 5;
|
||||||
|
const int margin = 10;
|
||||||
|
int x = margin;
|
||||||
|
int y = height() - margin;
|
||||||
|
int lineHeight = painter.fontMetrics().height();
|
||||||
|
const QList<Feature*>& features = m_document->features();
|
||||||
|
QString docName = m_document->fileName();
|
||||||
|
|
||||||
|
int maxWidth = painter.fontMetrics().horizontalAdvance(docName);
|
||||||
|
|
||||||
|
for (const Feature* feature : features) {
|
||||||
|
maxWidth = std::max(maxWidth, painter.fontMetrics().horizontalAdvance(" " + feature->name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int boxWidth = maxWidth + 2 * padding;
|
||||||
|
int boxHeight = (features.size() + 1) * lineHeight + 2 * padding;
|
||||||
|
|
||||||
|
y -= boxHeight; // Adjust y to be the top of the box
|
||||||
|
|
||||||
|
// Draw transparent background
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(QColor(50, 50, 50, 150));
|
||||||
|
painter.drawRoundedRect(x, y, boxWidth, boxHeight, 3, 3);
|
||||||
|
|
||||||
|
// Draw text
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
int currentY = y + padding + lineHeight;
|
||||||
|
int textX = x + padding;
|
||||||
|
|
||||||
|
painter.drawText(textX, currentY, docName);
|
||||||
|
currentY += lineHeight;
|
||||||
|
|
||||||
|
for (const Feature* feature : features) {
|
||||||
|
painter.drawText(textX + 10, currentY, feature->name());
|
||||||
|
currentY += lineHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
class ViewCube;
|
class ViewCube;
|
||||||
class SketchGrid;
|
class SketchGrid;
|
||||||
|
class Document;
|
||||||
|
class Feature;
|
||||||
|
|
||||||
class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||||
{
|
{
|
||||||
@@ -27,6 +29,7 @@ public:
|
|||||||
~ViewportWidget();
|
~ViewportWidget();
|
||||||
|
|
||||||
void startSketch(SketchPlane plane);
|
void startSketch(SketchPlane plane);
|
||||||
|
void setDocument(Document* document);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initializeGL() override;
|
void initializeGL() override;
|
||||||
@@ -40,10 +43,12 @@ protected:
|
|||||||
private:
|
private:
|
||||||
QVector3D project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport);
|
QVector3D project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport);
|
||||||
void drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection);
|
void drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection);
|
||||||
|
void drawFeatureBrowser(QPainter& painter);
|
||||||
|
|
||||||
QMatrix4x4 projection;
|
QMatrix4x4 projection;
|
||||||
ViewCube* m_viewCube;
|
ViewCube* m_viewCube;
|
||||||
SketchGrid* m_sketchGrid = nullptr;
|
SketchGrid* m_sketchGrid = nullptr;
|
||||||
|
Document* m_document = nullptr;
|
||||||
SketchPlane m_currentPlane = SketchPlane::NONE;
|
SketchPlane m_currentPlane = SketchPlane::NONE;
|
||||||
|
|
||||||
float xRot = 0;
|
float xRot = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user