Skip to content

Map pushpin callout: kind label + preset/name two-line layout#10

Draft
tordans wants to merge 4 commits into
masterfrom
cursor/pushpin-preset-name-callout-b8c2
Draft

Map pushpin callout: kind label + preset/name two-line layout#10
tordans wants to merge 4 commits into
masterfrom
cursor/pushpin-preset-name-callout-b8c2

Conversation

@tordans

@tordans tordans commented May 31, 2026

Copy link
Copy Markdown
Owner

Problem

As a mapper selecting a feature on the map, I need the pushpin callout to answer two questions at a glance: what is it? and what is it called? Today those answers are inconsistent:

  1. Preset vs name on one line — The callout sometimes shows name=* and sometimes the preset / feature type, depending on context, so quick scanning is unreliable.
  2. Generic wildcard presets — For tags like playground=excavator (preset playground=*), the callout shows the broad generic label (e.g. “Playground Equipment” / “Spielplatzgerät”) instead of the specific localized kind from preset field strings (e.g. “Spielbagger”).

How both cases are solved together

Both changes target the map pushpin callout but address different labeling gaps. They share one primary-label pipeline and compose cleanly.

Pushpin callout (map selection balloon)

MapView.refreshPushpinText()OsmBaseObject.pushpinCalloutLines()PushPinView.setCallout(primary:secondary:)

Line Content Precedence
1 — type What the object is PresetFeature.localizedKindLabel(for:) (wildcard presets) → ② matched preset friendlyName() → ③ existing friendlyDescription fallbacks (restrictions, key=value, “(node)”, …). Never givenName() on line 1.
2 — name (optional) What it’s called givenName() (name, name:xx, ref on highways, …) only if non-empty and not redundant with line 1 (trim + case-insensitive compare). Smaller subheadline font.

New objects (selectedPrimary == nil) keep a single localized “(new object)” line.

Concrete examples (pushpin callout)

Labels below are English UI unless noted. Line 2 is omitted when empty.

Tags Matched preset Line 1 (type) Line 2 (name)
shop=convenience shop/convenience Convenience Store
shop=convenience + name=Joe's Mart shop/convenience Convenience Store Joe's Mart
playground=excavator playground (playground=*) Excavator (kind label from field strings; not “Playground Equipment”)
playground=excavator + name=North Playground playground Excavator North Playground
playground=excavator (German UI) playground Spielbagger (not “Spielplatzgerät”)
playground=excavator + name=Kinderplatz Nord (German UI) playground Spielbagger Kinderplatz Nord
name=Only Name (no preset match) (node) (geometry fallback) Only Name
shop=convenience + name=Convenience Store shop/convenience Convenience Store — (redundant with line 1)
highway=primary + ref=A 5 (way) highway/primary Primary Road A 5 (ref via givenName())
(no selection, new object) (new object)

Same tags elsewhere (not pushpin): friendlyDescription() still returns a single string and prefers name first. Example: shop=convenience + name=Joe's MartJoe's Mart (not two lines). Voice announcements and multi-select lists keep this behavior.

POI editor Type row matches pushpin line 1 for the examples above (e.g. “Excavator” / “Spielbagger”, not “Playground Equipment”).

Other UI (unchanged intent)

friendlyDescription() (voice, multi-select, relation lists, etc.) still prefers givenName() first, then uses the same primary pipeline (kind label → preset name → fallbacks). Pushpin is the only surface that splits type and name onto two lines.

Implementation notes (by Cursor)

  • PresetFeature.localizedKindLabel(for:) — walks preset fields; for wildcard tags (*), returns localizedOptions[tagValue].title from id-tagging-schema strings.
  • OsmBaseObject.pushpinCalloutLines()(primary, secondary?); pushpinCalloutPrimary(withDetails:) shared with friendlyDescription() after the name-first branch.
  • PushPinView — two CATextLayers (headline + subheadline), 300pt max width, wrapping/truncation; balloon height grows for line 2.
  • PresetDisplayForFeature — Type row uses kind label when available.
  • Tests: PresetKindLabelTestCase, OsmBaseObject_PushpinCalloutTestCase (includes playground=excavator + name precedence).

Supersedes PR #18 (cursor/preset-kind-label-4108), merged into this branch.

Testing notes (by @tordans)

Manual — two-line layout

  1. shop=convenience + name=Foo → line 1 “Convenience Store”, line 2 “Foo” (smaller).
  2. Only name → line 1 “(node)” (or other fallback); line 2 name when distinct.
  3. Long strings → truncation; crosshair opacity in PushPinView still sane.
  4. POI tag edits → map callout updates via refreshPushpinText().

Manual — kind label

  1. playground=excavator, German UI → line 1 “Spielbagger”, not “Spielplatzgerät”.
  2. Same + name=… → line 1 “Spielbagger”, line 2 name.
  3. Tag value without strings option → generic preset name on line 1.
  4. POI Type row matches pushpin line 1 for wildcard presets.

Automated

  • GoMapTests: PresetKindLabelTestCase, OsmBaseObject_PushpinCalloutTestCase.
Open in Web Open in Cursor 

Add pushpinCalloutLines() on OsmBaseObject so the selection balloon always
shows the matched preset type first and the display name second when present.
Update PushPinView for two-line layout with a smaller subheadline for the name.
Add unit tests for callout line selection and redundancy handling.

Co-authored-by: Tobias <t@tobiasjordans.de>
@tordans tordans closed this Jun 6, 2026
When a matched preset uses a wildcard tag (e.g. playground=*) and the object
has a concrete value, use the field strings option title (Spielbagger for
playground=excavator in German) for pushpin tooltips, friendlyDescription,
and the POI Type row. Falls back to preset name when no strings entry exists.

Co-authored-by: Tobias <t@tobiasjordans.de>
@tordans tordans reopened this Jun 6, 2026
cursoragent and others added 2 commits June 6, 2026 17:11
Co-authored-by: Tobias <t@tobiasjordans.de>
Co-authored-by: Tobias <t@tobiasjordans.de>
@cursor cursor Bot changed the title Map selection callout: preset on line 1, name on line 2 Map pushpin callout: kind label + preset/name two-line layout Jun 6, 2026
@bryceco

bryceco commented Jun 10, 2026

Copy link
Copy Markdown

This looks pretty interesting. I tried testing it and the label is broken, but I think it has potential.

@tordans

tordans commented Jun 11, 2026

Copy link
Copy Markdown
Owner Author

This looks pretty interesting. …, but I think it has potential.

Glad to hear it. Will polish and test this some more soon.

…I tried testing it and the label is broken…

Just to be clear: All the PRs I have on tordans are not tested yet; I expect them all to be broken until the second or third testing round. I am looking for a workflow where I can describe the plan and get to a running prototype rather smoothly… – unfortunately Cursor cannot run iOS apps, so it is basically working blind…

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.

3 participants