Skip to content

Update ruler drawing for zero corners#202

Merged
pascalpp merged 43 commits into
pascal/193-zero-corner-helpers-v2from
pascal/196-ruler-drawing-update
Jun 14, 2026
Merged

Update ruler drawing for zero corners#202
pascalpp merged 43 commits into
pascal/193-zero-corner-helpers-v2from
pascal/196-ruler-drawing-update

Conversation

@pascalpp

Copy link
Copy Markdown
Owner

Summary

  • Draw horizontal and vertical ruler ticks from the selected zero corner instead of assuming top-left geometry.
  • Mirror tick labels, unit labels, and mouse-number values for right/bottom zero corners.
  • Keep mouse number labels clear of resize handles on either horizontal edge.

Validation

  • xcodebuild -project "Free Ruler.xcodeproj" -scheme "Free Ruler" test -only-testing:FreeRulerTests

Part of #192. Addresses #196.

@pascalpp pascalpp marked this pull request as ready for review June 13, 2026 06:21
Copilot AI review requested due to automatic review settings June 13, 2026 06:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates ruler layout/drawing to support all four “zero corner” configurations (top-left/top-right/bottom-left/bottom-right) by centralizing orientation-dependent geometry and mirroring tick/label/mouse-readout math accordingly. This aligns with the broader work in #192 and directly addresses the drawing requirements in #196.

Changes:

  • Introduces ZeroCornerGeometry plus RulerGrowthDirection/RulerSide to derive growth direction, tick/label sides, resize sides, and frame math from the selected zero corner.
  • Refactors horizontal/vertical tick rendering and mouse/unit label placement to use the new geometry (including mirrored readout values for flipped corners).
  • Updates resize-handle placement and resize-frame math to support resizing from either end depending on the active zero corner, with expanded unit test coverage for geometry and drawing helpers.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Free Ruler/Ruler.swift Adds ZeroCornerGeometry and updates default-frame calculations to be zero-corner aware.
Free Ruler/RulerController.swift Align/reset positioning now uses zero-corner geometry for consistent placement.
Free Ruler/HorizontalRule.swift Draws ticks/labels from the active zero edge and mirrors mouse/unit label logic for flipped corners.
Free Ruler/VerticalRule.swift Draws ticks/labels from the active zero edge and mirrors mouse/unit label logic for flipped corners.
Free Ruler/ResizeHandleView.swift Moves resize handle to the correct far edge and updates resizing math to work from either end.
FreeRulerTests/RulerCoreTests.swift Adds tests for zero-corner geometry, draw helper math, mirrored readouts, and resize behavior.
Free Ruler/de.lproj/MainMenu.strings Adds localization entries for the “Flip” menu/menu-item.
Free Ruler/es.lproj/MainMenu.strings Adds localization entries for the “Flip” menu/menu-item.
Free Ruler/fi.lproj/MainMenu.strings Adds localization entries for the “Flip” menu/menu-item.
Free Ruler/ja.lproj/MainMenu.strings Adds localization entries for the “Flip” menu/menu-item.
Free Ruler/zh-hans.lproj/MainMenu.strings Adds localization entries for the “Flip” menu/menu-item.
Comments suppressed due to low confidence (1)

Free Ruler/VerticalRule.swift:170

  • mouseNumberLabelRect always resolves collisions with the resize handle by pushing the mouse label upward (increasing origin.y). When the vertical resize handle is on the top edge (e.g. bottom zero-corners), this can push the label into/above the handle or even off the visible bounds. Adjust the collision logic to account for whether the handle is on the top or bottom half of the ruler and clamp the label rect accordingly.
        if let resizeHandleExclusionFrame = resizeHandleExclusionFrame {
            let minLabelBottom = resizeHandleExclusionFrame.maxY + mouseTickLabelResizeHandleSpacing
            labelRect.origin.y = max(labelRect.origin.y, minLabelBottom)
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pascalpp pascalpp changed the base branch from pascal/193-zero-corner-helpers to graphite-base/202 June 13, 2026 06:40
@pascalpp pascalpp changed the base branch from graphite-base/202 to pascal/193-zero-corner-helpers June 13, 2026 06:40
@pascalpp pascalpp changed the base branch from pascal/193-zero-corner-helpers to graphite-base/202 June 13, 2026 06:42
@pascalpp pascalpp changed the base branch from graphite-base/202 to pascal/193-zero-corner-helpers June 13, 2026 06:42
@pascalpp pascalpp changed the base branch from pascal/193-zero-corner-helpers to graphite-base/202 June 13, 2026 06:45
@pascalpp pascalpp force-pushed the graphite-base/202 branch from d176e65 to 9feb40a Compare June 13, 2026 06:45
@pascalpp pascalpp changed the base branch from graphite-base/202 to pascal/193-zero-corner-helpers-v2 June 13, 2026 06:45

pascalpp commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

@pascalpp pascalpp force-pushed the pascal/193-zero-corner-helpers-v2 branch from 9feb40a to 4b62670 Compare June 13, 2026 06:55
@pascalpp pascalpp force-pushed the pascal/196-ruler-drawing-update branch from 41ff15d to 45aae6d Compare June 13, 2026 06:55
@pascalpp pascalpp force-pushed the pascal/193-zero-corner-helpers-v2 branch from 4b62670 to f8e7c36 Compare June 13, 2026 16:07
Copilot AI review requested due to automatic review settings June 13, 2026 16:07
@pascalpp pascalpp force-pushed the pascal/196-ruler-drawing-update branch from 45aae6d to d19bbac Compare June 13, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

Free Ruler/VerticalRule.swift:170

  • mouseNumberLabelRect only avoids the resize handle when it’s on the bottom edge (it always pushes the label upward). With non-default zero corners, the vertical resize handle can be on the top edge (see ZeroCornerGeometry.resizeSide(for: .vertical)), which can cause the mouse number label to overlap the handle. Update the exclusion logic to handle both top and bottom handles (similar to the horizontal ruler’s midX check).
        if let resizeHandleExclusionFrame = resizeHandleExclusionFrame {
            let minLabelBottom = resizeHandleExclusionFrame.maxY + mouseTickLabelResizeHandleSpacing
            labelRect.origin.y = max(labelRect.origin.y, minLabelBottom)
        }

Comment thread Free Ruler/HorizontalRule.swift Outdated
Comment thread Free Ruler/VerticalRule.swift Outdated

@pascalpp pascalpp left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[codex reviewer] Findings:

[P1] The vertical mouse-number exclusion still assumes the resize handle is at the bottom. For .bottomLeft / .bottomRight, the vertical handle moves to the top, but mouseNumberLabelRect always raises labelRect.origin.y to at least resizeHandleFrame.maxY + spacing. Near a top-side handle that can put the label above the ruler bounds, so the mouse number disappears instead of moving below the handle. Please branch on the handle side, or clamp with a top-side constraint, when the vertical resize handle is above the tick label.

@pascalpp pascalpp force-pushed the pascal/193-zero-corner-helpers-v2 branch from f8e7c36 to c9f996c Compare June 14, 2026 07:15
pascalpp added 27 commits June 14, 2026 03:21
Introduce MouseTickLabelLayout to centralize mouse-tick label placement logic for both horizontal and vertical rulers, replacing per-rule mouseNumberLabelRect implementations. Add resize-handle obscuring support via setResizeHandleObscured and per-rule updateResizeHandleVisibility overrides so the resize handle fades when a mouse tick overlaps it; wire visibility updates into layout/preference changes and mouse-tick/showMouseTick setters. Update tests to reflect the new layout API and visual-obscuring behavior and remove the older mouseTickLabelResizeHandleSpacing constant.
Introduce debug-only preview tooling to visualize mouse tick label layout and offsets. Adds MouseTickLabelLayoutPreview (NSViewRepresentable) and MouseTickLabelLayoutPreviewView to draw ruler ticks, mouse tick line/label, unit label, and resize handle; plus SwiftUI helpers MouseTickLabelOffsetPreview and MouseTickLabelCornerPreview to show combinations of zero corners and orientations. Update RuleView_Previews to group horizontal/vertical ruler previews and include the new Mouse Tick Labels preview.
Replace direct prefs.zeroCorner usages with a RuleView.zeroCorner property and propagate that value to child views (UnitLabelView, ResizeHandleView, HorizontalRule, VerticalRule). Add frame(in:bounds, zeroCorner:) overloads and update layout code to use the passed zeroCorner. Introduce RuleView.installWindowBorder() and improve window size fallbacks. Add nil-checks for NSGraphicsContext before drawing label rectangles. Refactor DEBUG preview code: replace the old MouseTickLabelLayoutPreview with a compact MouseTickRulePreview that hosts new MouseTickPreviewHorizontalRule/VerticalRule subclasses, and wire preview configuration (previewZeroCorner, mouse positions, colors). Also add a new localized string key to Localizable.xcstrings.
Delete the NSViewRepresentable RuleViewPreview and the HStack of horizontal/vertical rule previews. Replace the previous preview group with a single MouseTickLabelOffsetPreview and adjust the preview layout/name. This simplifies SwiftUI previews by removing the AppKit bridging preview helper and duplicate preview entries.
Switch help icon naming from a build-number-based token to a UTC timestamp+hash token. Update FreeRuler HTML and CSS to reference the new freeruler-help-icon-<timestamp>-<hash>.png name, rename the icon file accordingly, and remove the old freeruler.png legacy copy. Update scripts/generate-app-icon.sh to generate a timestamped help_cache_token, drop the Info.plist build_number dependency, remove legacy copy behavior, and propagate the new token into styles.css and FreeRuler.html while cleaning up stale icons.
Introduce a CSS variable for the help icon and refresh related assets.

- FreeRuler.html: add :root style setting --free-ruler-help-icon, update styles.css query token, tidy metadata and reformat the keyboard shortcuts/feature sections.
- styles.css: switch .title-page-header background-image to use var(--free-ruler-help-icon).
- Replace old help icon with a new freeruler-help-icon PNG and remove the old file.
- Update multiple AppIcon image assets (various sizes) — regenerated icons.
- scripts/generate-app-icon.sh: combine perl substitutions to inject the cache token and set the --free-ruler-help-icon URL in the HTML, and remove an unused variable.

These changes allow the help page to reference the generated icon dynamically and support cache-busting when regenerating icons.
Add scripts/generate-help-index.sh which runs hiutil to build English.lproj.helpindex from Free Ruler/FreeRuler.help/Contents/Resources/English.lproj (script uses strict bash flags and executes from repo root). Wire the script into package.json as the "generate:help" npm script and update the packaged help index file accordingly so the help index can be regenerated as part of build tasks.
Use a fixed help bundle identifier and stop appending the build number. Updated FreeRuler.help/Contents/Info.plist to set CFBundleIdentifier to com.pascal.freeruler.help and adjusted CFBundleVersion to 491. Replaced the templated CFBundleHelpBookName in Free Ruler/Info.github.plist and Free Ruler/Info.plist with the fixed help ID. Removed the code in scripts/release/set-version.js that modified the help CFBundleIdentifier per-build so the help bundle ID remains stable across builds.
Introduce an adjustable preview for mouse tick label offsets used in DEBUG builds. Adds a mouseTickLabelPreviewRulerLength constant and refactors MouseTickLabelOffsetPreview into smaller views: heading, grid, controls, slider panel, and individual sliders with a numeric TextField (clamped and rounded). Replaces hardcoded 260 ruler length usage, extracts a cornerPreview helper, and updates the PreviewProvider to use the interactive controls for easier testing of label offsets.
Introduce RuleView.resizeHandleEndRegionContains(...) to encapsulate logic that determines whether the mouse tick overlaps the resize-handle end region based on ruler orientation and the current zeroCorner/resize side. Replace the inline min/max checks in HorizontalRule and VerticalRule with calls to this helper. Expand and rename unit tests to cover obscuring behavior from the leading edge to the ruler end across different zeroCorner configurations. Includes an assertionFailure fallback for unexpected cases.
Prevent mouse-tick/unit labels from overlapping the ruler resize handle and from incorrectly hiding near the zero edge. MouseTickLabelLayout now accepts an optional resizeHandleFrame and tickGap was renamed to tickLabelSpacing; layout logic was extended with horizontal/vertical helper checks to prefer the side that doesn't collide with the resize handle. RuleView gained unitLabelZeroRegionContains and HorizontalRule/VerticalRule use it to compute unit-label visibility based on growth direction and bounds. Debug previews and sliders were adjusted to exercise the new behavior, and unit tests were added to cover zero-edge hiding and label flipping around the resize handle.
Pass zeroCorner into child views and clean up geometry/layout logic. ResizeHandleView now computes grip and slot frames (gripRect/gripSize/slotFrame) and draws grip/bg relative to the grip; it accepts a zeroCorner override. UnitLabelView gets explicit padding, safer draw rect to leave room for descenders, and accepts zeroCorner for placement. MouseTickLabelLayout was extended to handle unitLabelFrame, vertical lanes, and revised offsets; added labelBackgroundFrame helper. HorizontalRule/VerticalRule use growthDirection-aware mouse tick line helpers and simplified unit label / resize-handle visibility checks. Tests updated and new unit tests added to cover the new layout behavior and zeroCorner override.
@pascalpp pascalpp merged commit 701c689 into pascal/193-zero-corner-helpers-v2 Jun 14, 2026
@pascalpp pascalpp deleted the pascal/196-ruler-drawing-update branch June 14, 2026 07:35
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.

2 participants