Interface mockup 17

This commit is contained in:
Dion Moult
2026-05-11 12:57:34 +10:00
parent a4f7db45cd
commit 9c1a10190d
8 changed files with 94 additions and 38 deletions
+39 -24
View File
@@ -1547,6 +1547,20 @@ void ViewportWindow::showAllElements() {
visibility_.showAll();
}
void ViewportWindow::invertElementVisibility() {
std::unordered_set<uint32_t> inverted;
for (const auto& [mid, m] : models_gpu_) {
if (m.hidden) continue;
for (const InstanceCpu& inst : m.instances) {
if (inst.object_id == 0) continue;
if (!visibility_.isHidden(inst.object_id)) {
inverted.insert(inst.object_id);
}
}
}
visibility_.setHidden(inverted);
}
void ViewportWindow::setCamera(float tx, float ty, float tz,
float dist, float yaw, float pitch) {
camera_target_ = QVector3D(tx, ty, tz);
@@ -1641,16 +1655,34 @@ void ViewportWindow::frameAabb(const QVector3D& mn, const QVector3D& mx,
void ViewportWindow::focusOnSelectedObject() {
if (camera_mode_ == CameraMode::Fps) return;
// F frames the *active* object so it's predictable across multi-select
// states. Framing the union of every selected member would be more
// expansive but ambiguous in a large set.
const uint32_t target = selection_.activeObjectId();
QVector3D mn, mx;
if (!computeObjectAabb(target, mn, mx)) {
const auto& sel = selection_.selectionIds();
if (sel.empty()) {
qDebug("Focus: no object selected or no AABB available");
return;
}
frameAabb(mn, mx, 1.30f); // a bit of headroom around small objects
bool found = false;
QVector3D lo(std::numeric_limits<float>::max(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::max());
QVector3D hi(-std::numeric_limits<float>::max(),
-std::numeric_limits<float>::max(),
-std::numeric_limits<float>::max());
for (uint32_t object_id : sel) {
QVector3D mn, mx;
if (!computeObjectAabb(object_id, mn, mx)) continue;
for (int a = 0; a < 3; ++a) {
if (mn[a] < lo[a]) lo[a] = mn[a];
if (mx[a] > hi[a]) hi[a] = mx[a];
}
found = true;
}
if (!found) {
qDebug("Focus: no object selected or no AABB available");
return;
}
frameAabb(lo, hi, 1.30f);
}
void ViewportWindow::viewAll() {
@@ -1758,23 +1790,6 @@ void ViewportWindow::keyPressEvent(QKeyEvent* event) {
}
return;
}
// K toggles the section tool.
if (key == Qt::Key_K
&& event->modifiers() == Qt::NoModifier
&& !event->isAutoRepeat()) {
toggleSectionTool();
return;
}
// Shift+K clears every section plane (and the selection).
if (key == Qt::Key_K
&& event->modifiers() == Qt::ShiftModifier
&& !event->isAutoRepeat()) {
clearSectionPlanes();
section_plane_selected_ = -1;
section_drag_active_ = false;
section_drag_index_ = -1;
return;
}
// While the section tool is active: Esc exits the tool, Delete removes
// the selected plane.
if (section_tool_active_) {
+6 -4
View File
@@ -351,6 +351,9 @@ public:
// Model-level `hidden` flags are not touched — a hidden model stays
// hidden, matching the user's expectation of "show all *elements*".
void showAllElements();
// Flip element-level visibility across every live element in visible
// models. Model-hidden objects are skipped and remain model-hidden.
void invertElementVisibility();
// Extended pick: returns the object id, world-space hit point, and
// world-space surface normal at (x, y). Renders the same pick pass as
@@ -399,10 +402,9 @@ public:
void setBenchmarkFrames(int n);
QString cameraString() const;
// Move camera_target_ to the selected object's world-AABB centroid and
// dolly camera_distance_ so the object's bounding sphere fits the
// current viewport. Yaw/pitch are preserved. No-op if no object is
// selected or its AABB is unknown.
// Move camera_target_ to the selected set's world-AABB centroid and
// dolly camera_distance_ so the union fits the current viewport.
// Yaw/pitch are preserved. No-op if no selected object has an AABB.
void focusOnSelectedObject();
// Frame the union of all finalized models. No-op if the scene is empty.
void viewAll();
+13 -3
View File
@@ -110,6 +110,12 @@ void MainWindow::setupChrome() {
bind_shortcut(QKeySequence(Qt::SHIFT | Qt::Key_F), [this]() {
viewport_controller_->setFlyMode();
});
bind_shortcut(QKeySequence(Qt::Key_K), [this]() {
viewport_controller_->toggleSectionMode();
});
bind_shortcut(QKeySequence(Qt::SHIFT | Qt::Key_K), [this]() {
viewport_controller_->clearSectionPlanes();
});
bind_shortcut(QKeySequence(Qt::Key_H), [this]() {
viewport_controller_->hideSelectedElements();
});
@@ -212,7 +218,7 @@ QWidget* MainWindow::buildNavigateRibbonPage() {
});
auto* view_selected = components::buttons::makeButton("View Selected", ":/icons/cube-scan-solid.svg", this);
connect(view_selected, &QToolButton::clicked, this, [this]() {
if (viewport_widget_) viewport_widget_->viewport()->focusOnSelectedObject();
viewport_controller_->focusSelectedObject();
});
auto* plan_view = components::buttons::makeButton("Plan", ":/icons/planimetry.svg", this);
@@ -243,10 +249,14 @@ QWidget* MainWindow::buildNavigateRibbonPage() {
connect(fly_mode, &QToolButton::clicked, this, [this]() {
viewport_controller_->setFlyMode();
});
auto* section_mode = components::buttons::makeButton("Section", ":/icons/cube-cut-with-curve.svg", this);
connect(section_mode, &QToolButton::clicked, this, [this]() {
viewport_controller_->toggleSectionMode();
});
row->addWidget(components::buttons::makeButtonGroup("CAMERA", {set_home, go_home, view_all, view_selected}, this));
row->addWidget(components::buttons::makeButtonGroup("ORIENTATION", {plan_view, front_view, side_view, align_object, projection_button}, this));
row->addWidget(components::buttons::makeButtonGroup("MODE", {fly_mode}, this));
row->addWidget(components::buttons::makeButtonGroup("MODE", {fly_mode, section_mode}, this));
row->addStretch(1);
return page;
}
@@ -272,7 +282,7 @@ QWidget* MainWindow::buildInspectRibbonPage() {
});
auto* invert_selection = components::buttons::makeButton("Invert", ":/icons/intersect.svg", this);
connect(invert_selection, &QToolButton::clicked, this, [this]() {
session_state_->setStatusMessage("Selection", "Invert selection coming soon");
viewport_controller_->invertSelection();
});
auto* distance = components::buttons::makeButton("Distance", ":/icons/select-edge3d.svg", this);
@@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.52844 7.29346L9 10.3332" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22 2L20 2M12 12L12 10C12 6.45478 14.3061 3.44817 17.5 2.39838" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M22 12L20 12M12 22L12 20C12 16.4548 14.3061 13.4482 17.5 12.3984" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 22L3.30861 17.1715C3.11813 17.0656 3 16.8649 3 16.647L2.99998 7.35304C2.99998 7.13514 3.11812 6.93437 3.3086 6.82855L11.7086 2.16188C11.8898 2.06121 12.1102 2.06121 12.2914 2.16188L15 3.66667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 11.9999L3.52842 7.29346" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 21L12 12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 13.5L15 4" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,6 +0,0 @@
<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.0028 3V7.49704C22.0028 7.77482 21.7776 8 21.4998 8V8C21.2999 8 21.12 7.88104 21.034 7.70059C19.4262 4.32948 15.9866 2 12.0028 2C6.81746 2 2.55391 5.94668 2.05219 11" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 16.4V9.39365C6 9.06228 6.26863 8.79365 6.6 8.79365H7.77283C7.97677 8.79365 8.16674 8.69006 8.2772 8.51863L9.7228 6.27502C9.83326 6.10359 10.0232 6 10.2272 6H13.7728C13.9768 6 14.1667 6.10359 14.2772 6.27502L15.7228 8.51863C15.8333 8.69006 16.0232 8.79365 16.2272 8.79365H17.4C17.7314 8.79365 18 9.06228 18 9.39365V16.4C18 16.7314 17.7314 17 17.4 17H6.6C6.26863 17 6 16.7314 6 16.4Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.05078 21V16.503C2.05078 16.2252 2.27596 16 2.55374 16V16C2.75366 16 2.93357 16.119 3.01963 16.2994C4.62737 19.6705 8.06703 22 12.0508 22C17.2361 22 21.4997 18.0533 22.0014 13" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

+1 -1
View File
@@ -22,8 +22,8 @@
<file alias="building.svg">icons/building.svg</file>
<file alias="cellar.svg">icons/cellar.svg</file>
<file alias="perspective-view.svg">icons/perspective-view.svg</file>
<file alias="rotate-camera-right.svg">icons/rotate-camera-right.svg</file>
<file alias="drone.svg">icons/drone.svg</file>
<file alias="cube-cut-with-curve.svg">icons/cube-cut-with-curve.svg</file>
<file alias="folder-plus.svg">icons/folder-plus.svg</file>
<file alias="folder-minus.svg">icons/folder-minus.svg</file>
<file alias="folder.svg">icons/folder.svg</file>
@@ -235,6 +235,20 @@ void ViewportController::setFlyMode() {
session_state_->setStatusMessage("Mode", "Fly mode active");
}
void ViewportController::toggleSectionMode() {
viewport_->toggleSectionTool();
if (viewport_->sectionToolActive()) {
session_state_->setStatusMessage("Section", "Section tool active");
} else {
session_state_->setStatusMessage("Section", "Section tool off");
}
}
void ViewportController::clearSectionPlanes() {
viewport_->clearSectionPlanes();
session_state_->setStatusMessage("Section", "Section planes cleared");
}
void ViewportController::toggleDistanceMode() {
viewport_->toggleLengthTool();
}
@@ -247,6 +261,10 @@ void ViewportController::toggleVolumeMode() {
viewport_->toggleVolumeTool();
}
void ViewportController::focusSelectedObject() {
viewport_->focusOnSelectedObject();
}
void ViewportController::hideSelectedElements() {
viewport_->hideSelectedElements();
}
@@ -259,6 +277,10 @@ void ViewportController::showAllElements() {
viewport_->showAllElements();
}
void ViewportController::invertSelection() {
viewport_->invertElementVisibility();
}
void ViewportController::updateVolumeReadout() {
if (viewport_->toolMode() != ViewportWindow::ToolMode::Volume) return;
@@ -44,12 +44,16 @@ public:
void setHomeView();
void goHomeView();
void setFlyMode();
void toggleSectionMode();
void clearSectionPlanes();
void toggleDistanceMode();
void toggleAreaMode();
void toggleVolumeMode();
void focusSelectedObject();
void hideSelectedElements();
void isolateSelectedElements();
void showAllElements();
void invertSelection();
private:
void applyCoordinateOperation(uint32_t mid);