Places map: city base map, cluster gallery, zoom + render polish

Base map / tiles:
- Switch the base map to the mapchart city-label world map; re-derive its
  Web-Mercator georeferencing (MAP_LON0/1, MAP_IMG_MY0/1) by least-squares
  against the pixel-identical graticule export.
- Add a 1.5x LANCZOS supersample LOD and bump tile quality 90->94 so city
  labels stay crisp when zoomed in (tools/png_to_tiles.py).
- Fill the map view background with the ocean colour instead of black.

Navigation / clustering:
- Snap the cluster grid to power-of-two zoom octaves so the bubbles stop
  jittering during a continuous zoom.
- Replace the loose zoom clamps with named MAP_SCALE_MIN/MAX (whole map fills
  the screen .. country/region level).
- Add a toggleable computed lat/lon graticule overlay (TRIANGLE).

Cluster gallery:
- Selecting a bubble now opens all its photos on the same justified grid as
  the timeline/search (a g_gallery_active filter). Members not already paged
  in are appended as hidden g_asset entries (kept out of the main timeline);
  a background metadata worker resolves each one's date/aspect so the grid
  reflows into month sections + true aspect ratios.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uKJQMYDE9Nrq9ECsU3MxH
This commit is contained in:
Sads
2026-06-18 22:26:59 +02:00
co-authored by Claude Opus 4.8
parent 02f428a76d
commit 5a0eb06d3e
8 changed files with 408 additions and 59 deletions
+35
View File
@@ -63,6 +63,29 @@ static int g_sect_count;
static int g_sect_cap;
static float g_content_h; /* total scrollable height incl. headers */
/* map cluster gallery: the photos of one map bubble, shown on the SAME grid as
* the timeline/search — a filtered view like g_search_*. g_gallery_idx holds
* indices into the g_asset_* arrays for the bubble's members; members not
* already paged into the library are appended as g_asset entries flagged
* g_asset_hidden (so they appear only here, never in the main timeline). Their
* date/aspect are resolved lazily by the metadata worker below, so the grid
* reflows into real month sections + true aspect ratios as they arrive. */
static int g_gallery_active;
static int *g_gallery_idx;
static int g_gallery_count;
static int g_gallery_cap;
/* background metadata resolver: a one-slot handoff (mirroring the thumb worker)
* that fetches one asset's date/aspect so the justified grid can place it. */
enum { META_IDLE, META_PENDING, META_DONE };
static volatile int g_meta_state = META_IDLE;
static char g_meta_id[40]; /* asset id to resolve (main -> worker) */
static int g_meta_target; /* g_asset index to fill (main-thread owned) */
static char g_meta_date[DATELEN]; /* results (worker -> main) */
static float g_meta_ratio;
static unsigned char g_meta_rot;
static int g_meta_is_video;
/* free-text smart (CLIP) search. when active the grid shows only the matching
* server assets — still date-grouped under month headers like the timeline —
* instead of the full merged library; TRIANGLE opens the keyboard, CIRCLE (or
@@ -159,6 +182,7 @@ static int grow_assets(int need)
!GROW(g_asset_rot, c, need) ||
!GROW(g_asset_is_video, c, need) ||
!GROW(g_asset_local_backed, c, need) ||
!GROW(g_asset_hidden, c, need) ||
!GROW(g_thumb, c, need) ||
!GROW(g_thumb_failed, c, need) ||
!(g_asset_cap = GROW(g_tex_err, c, need)))
@@ -214,6 +238,17 @@ static int grow_sect(int need)
return 1;
}
static int grow_gallery(int need)
{
if (need <= g_gallery_cap)
return 1;
int cap = GROW(g_gallery_idx, g_gallery_cap, need);
if (!cap)
return 0;
g_gallery_cap = cap;
return 1;
}
static void log_line(const char *fmt, ...)
{
FILE *f = fopen(LOG_PATH, "a");