Skip to content

Properties Menu — part resizing, size cycling, and bug fixes#91

Open
Cranezz wants to merge 20 commits into1.3.7from
feature/properties-menu
Open

Properties Menu — part resizing, size cycling, and bug fixes#91
Cranezz wants to merge 20 commits into1.3.7from
feature/properties-menu

Conversation

@Cranezz
Copy link
Copy Markdown
Collaborator

@Cranezz Cranezz commented Mar 4, 2026

Summary

Adds a fully featured Properties Menu, resizing tools for all part types, and a new snap system for movement. Also includes a round of bug fixes discovered during testing.

New features

  • Properties Menu — runtime-built panel showing part name, parameters, editable position and rotation fields, a local/global space toggle, and a snap toggle
  • Aluminum hole-count resizing — integer input + flip button to choose which end extends; translucent red/green ghost preview; undo/redo support
  • Plate resizing — editable Length and Width fields with flip buttons; ghost preview showing only the added or removed area with no overlap; undo/redo support
  • Shaft resizing — editable Length field with flip button; ghost preview for the delta section; undo/redo support
  • Screw / standoff / spacer size cycling — ◄/► arrow buttons and scroll wheel cycle through available sizes; when connected to a hole the anchored end stays fixed and only the free end extends
  • Snap controls — snap toggle moved from the toolbar into the Properties Menu (next to Local Space). Holding Shift snaps movement to 0.5-unit increments; Ctrl to 0.25-unit increments. The toggle also enables 0.25-unit snapping. Snapping is relative to where the drag started, not world origin. Old toolbar snap button removed from the scene.

Bug fixes

  • Properties menu closed when cycling screw/standoff sizes (was updating the wrong SelectionManager)
  • Ghost previews persisted after deleting a part mid-edit; stale input values appeared on the next selection
  • Switching to a different plate or shaft while edits were pending kept the old values in the input fields
  • ◄/► and scroll wheel wrapped around at min/max size instead of stopping
  • IndexOutOfRangeException for Spacer when param2 state was not fully restored
  • MissingReferenceException in HoleCollider when a connected HoleDetector had been destroyed
  • Aluminum resizer now breaks group connections before destroying holes so screws detach correctly
  • Movement snapping was jittery due to DOTween animation; fixed by snapping the target position rather than a delta from the animating transform
  • Snapping along one axis was rounding all three world axes, causing the object to jump sideways; fixed by snapping only the moving component

Cranezz and others added 14 commits March 3, 2026 09:28
Clamping now only applies when the user finishes editing (onEndEdit),
not on every keystroke (onValueChanged). Previously, typing a value
like 12.2 would instantly snap back to 12 because 12.2 exceeded the
max limit before the full decimal was entered.

Also replaced float.Parse with float.TryParse throughout to prevent
crashes on malformed input. Added XML doc comments for future contributors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Param Display prefab had m_CharacterLimit set to 3, which meant
users could only type 3 characters (e.g. "2.5" or "12") and could not
enter values like "2.564" or "12.2" even when under the allowed range.
Changed to 0 (unlimited) so any valid decimal can be entered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Properties Menu (PropertiesMenuUI.cs):
- New panel that shows part info when an object is selected
- Displays part name, group (Structure/Motion/Electronics), and up to
  two parameters (e.g. Size: 1x2, Length: 20 holes)
- Editable Position X/Y/Z and Rotation X/Y/Z fields that update the
  object in real time as the user types
- Scroll wheel support via ScrollableInputField helper component

Part data (PartName.cs + generators):
- Added param1Label, param1Display, param2Label, param2Display fields
  to PartName so placed parts carry their display properties
- All generators (Aluminum, Plate, Shaft) now populate these fields

Rotation ring snapping (RotateRing.cs):
- Hold Shift: snap to 15 degree increments
- Hold Ctrl: snap to 5 degree increments
- Snapping is now global (rounds final euler angles to absolute values
  from 0) so a part at 2.3 snaps to 5, 10, etc. not 7.3, 12.3

Rotation ring size (Rotate Ring.prefab):
- Scaled rings up 50% (0.01 -> 0.015) to make them easier to click

NOTE: The Properties Menu panel still needs to be wired up in Unity.
See PropertiesMenuUI.cs header comment for setup instructions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous version required lots of manual Inspector wiring which is
difficult for new contributors. This version creates all UI elements
(panel, text labels, colored input fields) entirely in code at startup.

Setup is now just: Create Empty → Add Component → PropertiesMenuUI.
No further Inspector steps needed. The script finds the Canvas and
SelectionObjectLink automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… canvas

FindObjectOfType<Canvas>() was returning whichever canvas Unity happened to
find first — often a World Space tool canvas — causing the panel to render
inside the 3D scene instead of as a screen overlay. Now loops all canvases
and picks the one with renderMode == ScreenSpaceOverlay.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- RotateRing: replace Input.GetKey (old system) with Keyboard.current
  (new Input System) so Shift/Ctrl snap no longer throws an exception
- Rotate Ring prefab: scale increased from 0.015 → 0.025 (2.5x original)
  to make rings clearly visible and easier to grab
- ScrollableInputField: add Init(inc, fmt) method for runtime configuration
- PropertiesMenuUI: add blue header bar to match app design language;
  offset panel right of the tool icon strip; rotation scroll now 5°
  instead of 0.1; position inputs now move the whole connected group
  (screws stay attached when you reposition a part via the fields)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Background now uses the project-wide 'Rounded Square' 9-slice sprite
  (found at runtime so no asset path is hardcoded) with the correct
  0.26 gray that matches the transform buttons and sidebar panels
- Panel position moved to (115, -65) — clear of the tool icon strip
  and further down as requested
- Nested content area keeps padding away from the header edge
- Colors cleaned up to match the existing UI palette throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PropertiesMenuUI.cs:
- Rotation fields now use Transform.Rotate(Space.Self/.World) delta approach
  instead of Quaternion.Euler, eliminating ZXY-order artifacts where Z always
  appeared local and X/Y always appeared global regardless of the toggle
- Position fields in local mode move along the object's own local axes
  (Space.Self equivalent via Dot-product projection) and display the
  projection of world position onto each local axis
- LOCAL/GLOBAL headers for both position and rotation update on toggle
- lastKnownLocalRot tracks localRotation separately in local mode to avoid
  false external-change triggers from DOTween world-rotation tweens
- ClosestEuler() prevents 90°/270° normalisation flips on external re-sync
- Font search now uses FindObjectsOfType<Text>(true) to include inactive
  objects, avoiding accidental Bold variant pickup; axis letters changed
  from FontStyle.Bold to Normal to match the rest of the UI

RotateRing.cs:
- Removed dot-product local-axis remapping; rotVectorLink.Vector is already
  correct in both modes when matchRotation=true on the ring container
- Added IsLocalSpace static flag toggled by PropertiesMenuUI

Displacement.cs:
- Changed DOLocalRotateQuaternion → DORotateQuaternion since Orientation is
  always world-space

HoleFace.cs:
- Added Update() that re-positions the overlay every frame using the live
  holeData values kept current by HoleCollider.Update(), so the HoleFace
  follows the hole when the part is rotated or moved

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fixed some bugs with rotating the parts.
added a way to move the object locally and globally.
Removed old transformation tool options menu, no longer needed with the properties menu.
Changed properties menu to show in the bottom left for convenience.
Adds runtime hole-count resizing for C-channels, angles, rails, and
U-channels via the Properties Menu, with a live 3-D preview and undo/redo.

New files:
- AluminumResizeData.cs  – component attached to generated parts; stores
  subParts reference, current count, and PartName rebuild data.
- AluminumResizer.cs     – static utility: ApplyResize() rebuilds mesh +
  hole colliders in-place; CalcNewPosition() keeps one edge world-fixed;
  CalcPreviewCenter() / CalcArrowPos() drive the visual preview.
- ResizeElement.cs       – IElement snapshot for undo/redo: records hole
  count + world position before/after each resize.

Modified files:
- AluminumSubParts.cs        – exposes MaxHoleCount public property.
- AluminumPartGenerator.cs   – attaches AluminumResizeData on Generate().
- PropertiesMenuUI.cs        – adds a HOLES section (input field + Flip
  button) that appears only for resizable parts; on keystroke shows a
  red/green ghost mesh of the sections being removed/added plus a blue
  sphere at the modified edge; pressing Enter (EndEdit) commits the resize
  with full undo/redo support via StateSystem.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PartName is defined in the Parts_List namespace — AluminumResizer was
missing the using directive, causing CS0246 at compile time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ly apply

• AluminumResizer.ApplyResize – temporarily moves the part to world
  origin before calling GenerateHoles so Instantiate's world-space math
  places the new HoleColliders at the correct local positions relative to
  the part, then restores the original transform.

• PropertiesMenuUI – ghost preview mesh scaled to 1.005× to eliminate
  Z-fighting against the real part mesh during removal previews.

• PropertiesMenuUI – hole-count editor moved to sit immediately after the
  param rows (replacing the static "Length: N holes" param2Row while
  visible), matching where users already look for that info.

• PropertiesMenuUI – changes no longer apply on End-Edit; a green ✓ save
  button must be clicked to commit the resize.  The live red/green ghost
  preview still updates on every keystroke.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New resize features:
- Plate resizing: editable Length and Width fields with flip buttons,
  translucent ghost preview (green add / red remove), and undo/redo
- Shaft resizing: editable Length field with flip button, ghost preview
  for the added/removed delta section, and undo/redo
- Screw/standoff/spacer size change: ◄/► arrow buttons and scroll wheel
  cycle through available sizes; standoffs/spacers anchor to the
  connected hole end so the free end extends outward

Bug fixes:
- Wrong SelectionManager caused menu to close when cycling screw sizes
  (SelectionObjectLink now exposes its manager via Manager property)
- Ghost previews persisted after deleting a part; stale inputs appeared
  on next selection (both cleared when panel hides or object changes)
- Switching to a different plate/shaft kept unsaved edits in inputs
  (pending-change flags now reset on object change in Update)
- ◄/► and scroll at min/max size wrapped around instead of stopping
  (Mathf.Clamp replaces modulo in OnChildPartCycle)
- IndexOutOfRangeException for Spacer when param2 state was not restored
  in RefreshChildPartSection before calling GetParam2Options
- HoleCollider MissingReferenceException on destroyed HoleDetectors
- AluminumResizer now breaks group connections before destroying holes
  so screws detach correctly when resizing removes their shared holes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cranezz and others added 6 commits March 4, 2026 08:57
- Moved the snap toggle from the transform toolbar into the Properties
  Menu, placed next to the Local Space toggle. It controls the same
  PositionTool.snapping and RotateRing.snapping flags as before.

- Added modifier-key position snapping to PositionTool.MoveToPos(),
  mirroring how rotation snapping already works in RotateRing:
    Shift held → 0.25-unit increments
    Ctrl  held → 0.10-unit increments
    Snap toggle ON (no modifier) → 0.125-unit increments (unchanged)
    No modifier + toggle OFF → free movement (unchanged)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Removed the SnappingToggle GameObject from Main.unity — snapping is
  now controlled exclusively by the toggle in the Properties Menu
- Updated position snap increments to match a more natural grid:
    Shift held       → 0.50-unit increments
    Ctrl  held       → 0.25-unit increments
    Snap toggle ON   → 0.25-unit increments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous implementation rounded the displacement relative to the
object's current transform.position. Since DOTween animates movement
over 0.25 s, transform.position changes every frame mid-tween, so the
rounded delta produced a different (off-grid) result each frame,
causing jitter and making the snap toggle appear broken.

Switching to absolute world-position rounding (pos.Round(snapInc))
snaps to the same grid point every frame regardless of where the
object currently is in its tween, giving stable consistent snapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous approach rounded the full world position (all 3 axes).
For PositionAxis, the perpendicular components come from initObjPos
(the object's position at drag start), which is often NOT on the snap
grid (e.g. Y = 0.125 for a VEX beam). Rounding those caused the object
to jump sideways to unexpected positions — "snapping to random distances".

Fix: move snapping out of MoveToPos and into each subclass, where the
moving vs fixed components are known:
- PositionAxis: snap only the signed distance along the axis direction
- PositionPlane: snap only the in-plane component; leave the normal
  component (the plane's constant height) untouched
- PositionTool: expose GetSnapIncrement() for subclasses to share

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously snapping was relative to world zero, so an object at 1.12
with 0.25 snap would jump to 1.0 or 1.25 instead of 1.12, 1.37, 1.62.

Fix: store the object's position along the axis (initAxisDist) and
in-plane (initInPlane) at drag start in Initialize(), then snap the
delta from that origin in Move(). Snap targets are now always
initPos ± N×snapInc relative to where the drag began.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merged 1.3.7 (Updated Unity Version / Fixed rails) into
feature/properties-menu. Kept all changes from both sides:
- 1.3.7: Unity version update, rail save fix
- feature/properties-menu: SnappingToggle GameObject removed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant