Skip to content

UV Editor: read-only panel (issue #459)#759

Merged
fernandotonon merged 4 commits into
masterfrom
feature/uv-editor-panel-459
Jun 24, 2026
Merged

UV Editor: read-only panel (issue #459)#759
fernandotonon merged 4 commits into
masterfrom
feature/uv-editor-panel-459

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds UVEditorController + UVEditorPanel.qml — read-only UV layout viewer with island-colored triangles, optional diffuse texture background, UV0/UV1 channel picker, and pan/zoom/fit controls (Canvas2D, no GL).
  • Integrates as a bottom-docked tab alongside Context, Console, Dope Sheet, and Curve Editor; toggled from View menu and Objects toolbar UV button; visibility persisted via QSettings.
  • Includes UVEditorController_test.cpp covering island detection (single tri, multi-submesh, UV seam split) and selection-driven refresh.

Closes #459.

Test plan

  • ./build_local/bin/UnitTests --gtest_filter="UVEditorControllerTest.*" (4/4 pass)
  • Open mesh with UVs → View → UV Editor → islands render, Fit/100% center correctly
  • Toggle texture checkbox on textured mesh → diffuse preview appears behind wireframe
  • Switch UV0/UV1 channel on mesh with UV1 data
  • Panel tabs with Context/Console/Curve Editor at bottom

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Added a dockable UV Editor panel with pan/zoom, fit/reset view, UV0/UV1 channel selection, UV grid/island highlighting, and optional texture-background preview.
    • Integrated the UV Editor into the main window via menu/toolbar access with saved show/hide state.
  • Bug Fixes
    • Improved UV island detection and ensured the UV preview refreshes correctly when selection or edit state changes.
  • Tests
    • Expanded tests for UV island detection and controller update/toggle behaviors.

Introduces UVEditorController + UVEditorPanel.qml with island-colored UV layout, texture preview, pan/zoom/fit, and bottom-dock tab integration alongside Context/Console/Curve Editor. Includes headless island-detection unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97347b60-9a51-4827-81c8-74667584305b

📥 Commits

Reviewing files that changed from the base of the PR and between 1a677fb and 70896d6.

📒 Files selected for processing (5)
  • qml/UVEditorPanel.qml
  • src/UVEditorController.cpp
  • src/UVEditorController.h
  • src/UVEditorController_test.cpp
  • tests/CMakeLists.txt
✅ Files skipped from review due to trivial changes (1)
  • tests/CMakeLists.txt
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/UVEditorController.h
  • src/UVEditorController.cpp
  • qml/UVEditorPanel.qml

📝 Walkthrough

Walkthrough

Adds a dockable UV editor panel with a new QML controller, UV layout rendering, pan/zoom controls, texture background support, and MainWindow integration for docking, visibility persistence, and menu access.

Changes

UV Editor Panel and Controller

Layer / File(s) Summary
Controller contract and build wiring
src/UVEditorController.h, src/CMakeLists.txt, tests/CMakeLists.txt
Declares the UVEditorController QML singleton API, cached state, and helper declarations, and adds the controller implementation to the application and test build lists.
UV cache rebuild and texture source resolution
src/UVEditorController.cpp
Implements controller singleton lifecycle and signal wiring, UV extraction and island computation, diffuse texture source lookup, mesh filtering, cache rebuilding, and mesh-state updates from the current selection.
UV panel state, rendering, and interaction
qml/UVEditorPanel.qml
Defines the QML panel state and transform helpers, connects to controller updates, renders the status area, UV controls, texture background, grid, triangles, and input handling for panning and zooming.
MainWindow dock and menu wiring
src/mainwindow.cpp, src/mainwindow.h, src/qml_resources.qrc
Adds the UV editor dock, QML singleton registration, view-menu toggle, rail button, bottom-dock reveal support, tabification, visibility persistence, controller cleanup, and QML resource registration.
Controller behavior tests
src/UVEditorController_test.cpp
Adds mesh helpers and GTest coverage for island computation, UV-channel handling, selection refresh, and texture-background toggling.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MainWindow
  participant UVEditorController
  participant UVEditorPanel
  participant EditableMesh

  User->>MainWindow: Open UV Editor dock
  MainWindow->>UVEditorController: refresh()
  UVEditorController->>EditableMesh: read UV data and build islands
  UVEditorController-->>UVEditorPanel: meshDataChanged
  UVEditorPanel->>UVEditorPanel: rebuild cache and repaint canvas
  User->>UVEditorPanel: pan / zoom / fit
  UVEditorPanel->>UVEditorPanel: update transforms and requestPaint
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Poem

🐇 I hopped to the grid where UVs align,
Islands in color, tidy and fine.
Pan with a drag, zoom with a spin,
Fit to the bounds and let the view win.
A rabbit-approved panel now shines bright! 🌙

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing the required Technical Details section and the template's Features/Bugfixes subsections. Add a Technical Details section and the requested Features/Bugfixes subsections; include PS1 runtime rip items only if applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: a read-only UV editor panel.
Linked Issues check ✅ Passed [#459] The PR appears to satisfy the dockable read-only UV editor, Canvas2D rendering, pan/zoom, texture preview, channel picker, live updates, and tests.
Out of Scope Changes check ✅ Passed I don't see clear out-of-scope code changes; the edits support the UV editor, controller, QML resource, main window wiring, and test/build integration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/uv-editor-panel-459

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a677fbd66

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/UVEditorController.cpp Outdated
Comment thread src/UVEditorController.cpp Outdated
Comment thread src/UVEditorController.cpp Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/UVEditorController.cpp (1)

258-299: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add breadcrumbs around preview texture resolution and cache writes.

This code does both import-style lookup and export-style cache generation, but none of it is breadcrumbed. That leaves the new UV preview path pretty opaque when users report missing backgrounds.

As per coding guidelines, All user-facing actions and significant operations must be tracked with SentryReporter::addBreadcrumb(category, message) using category 'file.import'/'file.export' for I/O operations.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/UVEditorController.cpp` around lines 258 - 299, Add Sentry breadcrumbs in
resolveDiffuseTextureSource around each significant texture I/O step so the UV
preview path is traceable. Use SentryReporter::addBreadcrumb with category
file.import for lookup/resolution attempts and file.export for generating or
writing the cached embedded preview. Cover the key branches in
UVEditorController::resolveDiffuseTextureSource: loaded texture origin lookup,
EmbeddedTextureCache retrieval, preview file creation/saving, and fallback
filesystem candidate checks, keeping the messages specific to the texture name
and action.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@qml/UVEditorPanel.qml`:
- Around line 71-75: The `onMeshDataChanged()` handler in `UVEditorPanel.qml` is
auto-calling `fitToView()` for every `meshDataChanged()` signal, which also
fires from `UVEditorController::setShowTextureBackground()` and resets the
user’s view. Update the `onMeshDataChanged()` logic so it only fits to view when
the actual mesh/geometry changes, not when texture background visibility
changes; use the existing `UVEditorController`/`meshDataChanged` flow to
distinguish those cases and keep `rebuildTriangleCache()` behavior intact.
- Around line 215-218: The UV texture preview placement in UVEditorPanel.qml is
using parent-space coordinates while the UV mapping itself is based on
viewCanvas dimensions, so the image ends up offset from the wireframe. Update
the Image positioning/sizing logic (the block using root.uvToScreen and the
viewCanvas inset) to align against the canvas content rect instead of the outer
parent, and ensure the 1 px canvas inset is accounted for consistently in both
the preview Image and the canvas-based transform.

In `@src/UVEditorController_test.cpp`:
- Around line 67-70: Move the Ogre mesh-file prerequisite check out of
individual tests and into the fixture setup in UVEditorController_test,
alongside tryInitOgre(). In SetUp(), assert both ASSERT_TRUE(tryInitOgre()) and
ASSERT_TRUE(canLoadMeshFiles()) before any Ogre-dependent setup like
createStandardOgreMaterials(). Remove any GTEST_SKIP() usage for these
prerequisites in the affected tests so failures surface immediately in the
shared fixture setup.

In `@src/UVEditorController.cpp`:
- Around line 403-404: The preview submesh selection in
UVEditorController::resolveDiffuseTextureSource is nondeterministic because
QSet::constBegin() depends on hash iteration order. Change the logic that
computes previewSub to pick a stable submesh index from submeshFilter, such as
the smallest selected index, before passing it to resolveDiffuseTextureSource.
Keep the fix localized to the preview background selection path so multi-submesh
selections always resolve the same texture source.
- Around line 290-293: The texture fallback path search in UVEditorController
currently uses applicationDirPath() on macOS, which resolves under
Contents/MacOS instead of the .app bundle root. Update the candidate list in the
UV preview texture lookup to use macBundlePath() for the macOS-specific fallback
so bundled Ogre textures are resolved relative to the app bundle root, while
keeping the existing non-macOS fallbacks intact.
- Around line 200-211: The computeIslandsFromEditableMesh helper ignores its
uvChannel argument, so callers cannot select which UV set is used. Update
UVEditorController::computeIslandsFromEditableMesh to either remove uvChannel
from the API if it is not needed, or thread it through the mesh-to-half-edge
conversion so computeIslandsFromHalfEdgeMesh operates on the requested channel
instead of always using the default UV data.
- Around line 274-285: Sanitize the texture name before building the preview
cache path in UVEditorController::retrieve preview generation, because texName
is currently appended directly into outPath. Update the logic around the
QDir/QFileInfo and QImage save path construction to strip path separators,
dot-dot segments, and any absolute-path components so the cached PNG stays
inside uv_editor_previews. Use a safe filename derived from texName for the file
written by the preview cache code path.

---

Nitpick comments:
In `@src/UVEditorController.cpp`:
- Around line 258-299: Add Sentry breadcrumbs in resolveDiffuseTextureSource
around each significant texture I/O step so the UV preview path is traceable.
Use SentryReporter::addBreadcrumb with category file.import for
lookup/resolution attempts and file.export for generating or writing the cached
embedded preview. Cover the key branches in
UVEditorController::resolveDiffuseTextureSource: loaded texture origin lookup,
EmbeddedTextureCache retrieval, preview file creation/saving, and fallback
filesystem candidate checks, keeping the messages specific to the texture name
and action.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 49e2e129-a100-4a02-8fd8-51e760b24c8d

📥 Commits

Reviewing files that changed from the base of the PR and between db5a1df and 1a677fb.

📒 Files selected for processing (8)
  • qml/UVEditorPanel.qml
  • src/CMakeLists.txt
  • src/UVEditorController.cpp
  • src/UVEditorController.h
  • src/UVEditorController_test.cpp
  • src/mainwindow.cpp
  • src/mainwindow.h
  • src/qml_resources.qrc

Comment thread qml/UVEditorPanel.qml
Comment thread qml/UVEditorPanel.qml Outdated
Comment thread src/UVEditorController_test.cpp
Comment thread src/UVEditorController.cpp Outdated
Comment thread src/UVEditorController.cpp
Comment thread src/UVEditorController.cpp Outdated
Comment thread src/UVEditorController.cpp Outdated
fernandotonon and others added 2 commits June 24, 2026 12:27
Link UVEditorController into UnitTests, stabilize preview submesh selection, sanitize texture cache paths, and harden macOS bundle texture resolution.

Co-authored-by: Cursor <cursoragent@cursor.com>
Walk face half-edges directly, fan-triangulate canonical n-gon faces, clear stale UVs when a channel is missing, and only auto-fit when mesh revision changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fernandotonon

Copy link
Copy Markdown
Owner Author

Review feedback addressed

Follow-up commits on this branch (67a5048, d1ad8ce) cover the CodeRabbit/Codex review items:

  • CI link fix: UVEditorController.cpp added to tests/CMakeLists.txt so MaterialEditorQML_test links cleanly.
  • Island BFS: walk each face's own half-edges instead of faceEdges()edge().halfEdge.
  • N-gon meshes: fan-triangulate canonical faces when building draw data (matches HalfEdgeMesh face order).
  • UV channel switch: clear hasUV when the requested channel is absent on a submesh.
  • Texture preview: deterministic preview submesh (min_element), sanitized cache filenames, macOS bundle-root fallback, Sentry breadcrumbs on texture I/O.
  • QML UX: auto-fit only when meshRevision changes; texture Image offset by viewCanvas origin; texture toggle no longer emits meshDataChanged.
  • Tests: 5 UVEditorControllerTest cases (incl. texture toggle); Ogre/GL prerequisites asserted in fixture SetUp.

CI is green after re-running unit-tests-linux (first attempt was cancelled by runner shutdown, not a test failure).

Cover canonical quad-face island grouping and UV1 channel fallback when the second UV set is absent.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon fernandotonon merged commit 23e0ba2 into master Jun 24, 2026
55 of 57 checks passed
@fernandotonon fernandotonon deleted the feature/uv-editor-panel-459 branch June 24, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UV: Slice A — UV editor panel + read-only display

1 participant