Skip to content
macOSDeep Dive Published Updated 7 min readViews unavailable

NSRulerView on macOS: Coordinate Spaces, Units, and Editable Markers

Build dependable AppKit rulers by aligning document coordinates, measurement units, marker ownership, scrolling geometry, and edit validation.

NSRulerView is the AppKit component for a ruler above or beside a scroll view’s document. It can draw measurement marks, host accessory controls, and display markers that represent document elements such as margins, tab stops, or guides. A ruler is not just decorative chrome: it translates between a visual scale and the document’s coordinate model. If those spaces drift apart, dragging a marker can modify the wrong object or report an incorrect measurement.

Use a ruler only when its scale has a stable meaning in the document. A word processor might measure in points or inches; a timeline might map ruler positions to time; a canvas may use document units. Define the mapping once, then use it in drawing, hit testing, marker tracking, and model updates rather than independently recomputing offsets in each callback.

Attach the ruler to the document’s scroll view

The ruler is associated with an NSScrollView and a client view. The client is typically the document view or a subview of it. The ruler’s clientView reference is weak, so the scroll view and document hierarchy must retain the view for the ruler’s lifetime.

import AppKit

func installHorizontalRuler(for scrollView: NSScrollView) -> NSRulerView? {
    guard let documentView = scrollView.documentView else { return nil }
    let ruler = NSRulerView(scrollView: scrollView, orientation: .horizontalRuler)
    ruler.clientView = documentView
    ruler.ruleThickness = 24
    scrollView.horizontalRulerView = ruler
    scrollView.hasHorizontalRuler = true
    return ruler
}

The sample uses the document view as the client so marker locations naturally describe document positions. If a nested subview owns the geometry, set that view as the client and keep the conversion contract explicit. The view’s window coordinates, the ruler’s local coordinates, and the client view’s document coordinates are not interchangeable. Convert between them using AppKit view conversion APIs rather than adding a guessed scroll offset.

The scroll view controls whether its rulers are shown. Install the ruler object before enabling display, and test the result with scrollers, content insets, a resized window, and a magnified document. A ruler can be present but have no useful thickness, or can display values against a client view that has been replaced during document reload.

Choose and register measurement units

NSRulerView supports measurement units and can register custom units with a name, abbreviation, conversion factor, and step-up/step-down cycles. The conversion factor maps the unit to points. Use the same canonical unit in the document model, and use display units only as a presentation choice.

Do not treat a screen pixel as an invariant physical measurement. A point is a logical drawing unit, while display scaling and printer output introduce other coordinate transformations. For an editor that shows inches or centimeters, define how the document maps its model units to points and how that maps to export or print geometry. A ruler label that says “1 inch” does not make an arbitrary zoomed canvas print at one physical inch.

Spacing should adapt to zoom and available width. Keep major and minor tick calculations based on the visible document range and scale. Choose intervals that produce readable labels rather than drawing every possible subdivision. When zoom changes, invalidate the hash marks and recalculate labels using the new transform. Avoid assigning a fixed number of ticks per window width while ignoring document scale.

Use localized number formatting for visible labels, but keep model values locale-neutral. A comma decimal separator or localized unit name should not change the stored document coordinate. If the editor supports both physical and semantic units, such as points and frames, give the ruler an explicit measurement mode and update its accessibility labels when that mode changes.

Draw labels and hash marks in the right coordinate system

Custom subclasses can override hash-mark and label drawing when the standard ruler does not fit the document model. The drawing rectangle passed to the ruler’s drawing methods is in the ruler view’s coordinate space. Convert positions deliberately when referring to the client view. Respect flipped-coordinate behavior and the ruler orientation; horizontal and vertical rulers do not share the same axis convention.

Keep drawing deterministic and side-effect free. A draw pass can occur because the window exposed, resized, scrolled, or changed appearance. Do not update the document model, perform I/O, or create permanent markers during drawing. Compute tick layout from the current viewport and model snapshot, draw the visible portion, and invalidate hash marks when a scale or unit policy changes.

The ruler view exposes originOffset, which measures the zero mark from the bounds origin of the scroll view’s document view, in that document coordinate system. It is not an offset from the ruler’s own frame or necessarily from the client subview’s origin. If the document uses a nonzero origin, flipped view, or nested canvas, test the zero mark against known model coordinates at several scroll positions.

Markers represent model state

An NSRulerMarker has a location in the coordinate system of its ruler’s client view. It can carry a represented object and can be configured as movable or removable. Keep the authoritative marker data in the document model, not only in the marker view object. Rebuild or update the ruler markers from that model after undo, document reload, or a collaboration update.

The markers property replaces the ruler’s marker list and does not ask the client view to approve each marker. That makes it suitable for reflecting a model snapshot, but it means the app must validate the list before assigning it. Use a stable represented object identifier rather than a transient array index, and ensure the ruler has a client view before setting markers.

When a user drags a marker, convert the result to a model operation and validate it against current document constraints. The visual drag can begin under one revision while another task changes page size or ruler origin. At commit time, compare the document revision, clamp or reject invalid positions according to product rules, register one undoable transaction, and refresh the displayed marker from committed state.

If creating markers through trackMarker(_:withMouseEvent:), understand that AppKit forwards pointer tracking to the marker. The product still decides which marker type can be created, what it represents, and what happens if creation is canceled. A marker dropped at a visually valid location may still be invalid for the document, such as a margin that exceeds the page width.

Scroll, resize, and document lifecycle

A ruler is tiled with the scroll view. Changes in reserved thickness for markers or accessory views can affect the scroll view’s layout. If a custom marker is taller or wider than the default reservation, set the relevant reserved thickness before showing it to avoid repeated retiling. Keep accessory controls from covering labels or changing the coordinate origin unexpectedly.

When a document window switches to another document, update the ruler client and markers as one transition. Do not leave a marker list from the previous document attached while swapping the client view. If the ruler is shared, serialize which document currently owns it. Separate ruler identifiers or instances are clearer when different document types have incompatible measurement semantics.

Support accessibility alongside visual ticks. A number drawn into the ruler is not automatically an accessible value for a marker. Provide meaningful accessibility descriptions for custom controls, expose keyboard alternatives for operations that otherwise require dragging, and ensure zoom or unit changes are communicated to assistive technology.

Validation matrix

Test a zero-origin and nonzero-origin document, flipped and unflipped clients, horizontal and vertical orientation, zoom changes, unit changes, scroller appearance, document resizing, marker creation and removal, undo/redo, document replacement, and invalid marker movement. Assert the drawn label, model position, and exported document position agree for known reference points.

Capture the document revision, client identity, scroll bounds, ruler origin offset, zoom factor, unit, and marker ID in a support diagnostic. Avoid logging document content. When a marker appears at the wrong place, these values distinguish coordinate conversion, stale client ownership, zoom mapping, and model validation failures.

NSRulerView supplies ruler layout and marker mechanics. The application owns the measurement model, coordinate conversion, user-edit validation, persistence, and accessibility. Keep those responsibilities aligned, and the ruler remains a trustworthy editor for the document rather than an independent source of geometry.

Related:

Sources:

Comments