File Details
v0.2.0
- R
- May 12, 2026
- 919.08 KB
- 6
- 12.0.7+4
- MoP Classic + 1
File Name
SplitWatch-v0.2.0.zip
Supported Versions
- 12.0.7
- 12.0.5
- 12.0.1
- 12.0.0
- 5.5.0
SplitWatch
v0.2.0 (2026-05-12)
Full Changelog Previous Releases
- Merge beta → main: v0.2.0 final — .pkgmeta + release workflow + gitignore
- Add .pkgmeta + GitHub release workflow (BigWigsMods/packager)
.pkgmeta:- package-as: SplitWatch
- curse-project-id: 1541355
- wago-project-id: QNlzMEKe
- 5 externals fetched at build time (LibStub, CallbackHandler, LSM,
LibDataBroker, LibDBIcon) — same set as the bundled Libs/ folder, so
release zips contain upstream-fresh copies instead of our snapshots. - ignore list strips .gitignore, .github, README.md, LICENSE, root
logo.png, CLAUDE.md, CHANGELOG.md, .pkgmeta, scripts/ from the zip.
.github/workflows/release.yml: - Fires on any tag push.
- Runs BigWigsMods/packager@v2 with CF_API_KEY / WAGO_API_TOKEN /
GITHUB_TOKEN secrets. Same shape as BossWatch — drop in, tag,
and the packager handles CurseForge + Wago + GitHub release in one go.
User still needs to add the two repo secrets (CF_API_KEY from
curseforge.com/account/api-tokens and WAGO_API_TOKEN from
addons.wago.io/account/api) before the first tag.
- Honor expanded .gitignore — untrack CLAUDE.md
User expanded the .gitignore to cover OS junk, editor scratch, the full
.claude/ + .claude.local/ workspace + CLAUDE.md, .env secrets, packager
output (.release/ .pkgmeta.local *.zip *.tar.gz), runtime SavedVariables
(WTF/ *.lua.bak) and *.log. CLAUDE.md was the only file already tracked
that the new patterns cover — git rm --cached so the local copy stays
but the repo no longer contains it. - Merge beta → main: v0.2.0 — constraints, Item Level source, resize, CF/Wago IDs
v0.2.0 release contents (all features shipped on beta since 0.1.0):- Team-composition constraints: Battle Rez, Bloodlust (default ON), melee/ranged, Mass Dispel, Decurse (default OFF)
- Item Level (inspect) as 5th weight source via Blizzard API
- Resizable panel with persisted size + UIParent clamp at load
- Logical re-org: Contraintes on Joueurs tab, live Source preview on Réglages
- Per-player ilvl/DPS suffix on team columns
- Source-used line on Preview tab
- Team size rebalance after per-role snake (no more 11/9 in a 20-man)
- Escape closes the panel
- Refresh-chain fix after ScrollFrame wrap
- README realigned, CurseForge + Wago project IDs + badges added
- .claude/ and .env added to .gitignore
- Add CurseForge + Wago project IDs + untrack .claude state
TOCs: X-Curse-Project-ID 1541355, X-Wago-ID QNlzMEKe.
README: badges linking to both publishing portals.
.gitignore: ignore .claude/ (Claude Code workspace state) and .env / .env.*
(secrets). Untrack the previously-committed .claude/settings.local.json. - README: realign with v0.2.0 surface area
Reflects the actual current addon: 5 weight sources (added Item Level via
inspect), 5 toggleable team-composition constraints (BR / Lust / melee-
ranged / Mass Dispel / Decurse), resizable panel, ilvl/DPS suffix on team
columns, source-used line on Preview, Escape-to-close, full FR locale.
Drops the per-feature blurbs that no longer matched the UI (the 'Players
tab is just sliders' description, the missing constraint mention, the
missing resize feature). Added a new 'Standalone — 0 required addons'
badge to the title block for instant scannability. - Réglages: bring back the live source preview
Removed too aggressively in the previous re-org. The inline [ilvl X] /
[245.6k] suffixes on team columns only show up AFTER computing a split,
so users have no way to verify their damage meter is wired up before
hitting Calculer. Put the live preview back on Réglages between Source
DPS and Permission status (y=-340), with a hint that calls out its
diagnostic purpose. Auto-refresh ticker (1.5s) still attached to the
Réglages tab's outer ScrollFrame so it only ticks while the tab is
visible. - Resizable main frame + logical re-org (Constraints → Joueurs)
Resize:- Panel min 720x500, max 1400x1100, default 720x540. Persisted size restored
on open and clamped against UIParent dimensions (no off-screen overflow
when moving to a smaller monitor). - BOTTOMRIGHT grip with UI-ChatIM-SizeGrabber textures; updates panelW/panelH
on mouse-up. ScrollFrame OnSizeChanged grows content height to fill the
viewport when the panel gets taller so no empty band shows under the last
section.
Re-org — Réglages was a dumping ground (5 sections); split logically: - Réglages now contains only Général + Source DPS + Permissions + Classic
banner. Removed the 'Aperçu de la source' section: the data is now visible
inline next to each player on the Aperçu tab's team columns (the [ilvl X]
/ [245.6k] suffix shipped in v0.2.0), so the dedicated live preview was
redundant. - Joueurs gains the Contraintes section at the top — composition rules
conceptually belong with the player roster + Manual weight sliders, not
with the addon-level settings. Manual-weights section now starts at
y=-210, scroll at -258 with 280px height, action buttons at -550. - Manual-weights hint now reminds the reader the sliders are only used
when source = Manual.
- Panel min 720x500, max 1400x1100, default 720x540. Persisted size restored
- v0.2.0: constraint resolver — Battle Rez / Lust / melee-ranged / dispels
The RL can now require composition rules that the algorithm enforces with
minimal-disruption swaps. Each constraint is independently toggleable on a
new 'Constraints' section of the Réglages tab. Defaults: Battle Rez ON,
Bloodlust ON, the rest OFF.
Splitter additions:- CONSTRAINTS table: class sets for BR / LUST / MASS_DISPEL / DECURSE.
- CLASS_RANGE table: melee/ranged classification (Druid/Shaman/Hunter
default to RANGED — the more common DPS spec). entry.attackRange
overrides the default so a future inspect-spec scan can refine it. - ensurePresence(constraint): if one team lacks the class, find the DPS
pair with the smallest score delta and swap. Records
CONSTRAINT_MISSING_<id> or CONSTRAINT_UNSWAPPABLE_<id> in warnings
when the swap is impossible. - Melee/ranged equaliser: count melee per team and swap melee↔ranged DPS
until the diff is ≤ 1. 20-iteration guard against pathological cases. - Constraint pass runs AFTER the team-size rebalance, so basic shape
guarantees (gap ≤ 1) are preserved before composition rules kick in.
UI: - Setup → new 'Constraints' section with 5 NEW-badged checkboxes.
- Preview → new warning strings for every CONSTRAINT_MISSING_* and
CONSTRAINT_UNSWAPPABLE_* case (with full FR translations).
TOCs bumped to 0.2.0. CHANGELOG.md gains a full [0.2.0] section and
the in-addon Changelog tab leads with the v0.2.0 entry above v0.1.0.
- Panel: close on Escape via UISpecialFrames
Register SplitWatchOptionsPanel in Blizzard's UISpecialFrames list so the
panel responds to Escape like every other Blizzard UI window. One-liner
that I missed when porting the BossWatch panel skeleton. - Fix refresh chain after ScrollFrame wrap — content holds .refresh
Regression introduced when each tab page got wrapped in a ScrollFrame:
pages[id] now points at the SF, but builder code sets parent.refresh on
the content child (sf.content). Both the module-level refresh closure
(used by every widget factory's onChange) and selectTab's tab-switch
hook called pages[id]:refresh() directly — which is nil, so the call
was a no-op and side-effects like _syncIlvlBtn() never ran. Symptom
reported by the user: selecting the Item Level source left the
'Scan raid ilvl' button greyed out forever.
Both call sites now unwrap p.content first. - Setup: 'Scan raid ilvl' button is disabled unless ILVL source is selected
The inspect cache feeds only the Item Level source — scanning while a
damage meter is active is wasted work. Wire a _syncIlvlBtn() callback
into parent.refresh so picking a source in the dropdown immediately
re-evaluates the button enabled state. Tooltip updated to spell out the
requirement. - Preview: surface which damage-meter source is feeding the algorithm
Adds a 'Source used for the split: <label>' line below the roster-status
line on the Preview page (label same as Réglages → Active source — e.g.
'Details!', 'Item Level (inspect) — 12 cached', 'Manual', etc.). Saves
the round-trip to the Réglages tab when you just want to confirm what
the algorithm is reading.
Layout: Before/After labels and stats blocks pushed down by 18px to make
room. Team-column titles unchanged at y=-200. - Splitter: rebalance team sizes after per-role distribution
Bug: snake-distributing tanks, healers, and DPS independently can produce
team counts that diverge by 2 when role counts are odd. Example from a
real 20-man pull (2T + 1H + 17DPS):- tanks alternate → A=1, B=1
- 1 healer to A → A=2, B=1
- 17 DPS snake by DPS→ A=2+9=11, B=1+8=9 ← gap of 2
Add a rebalance pass after the per-role loops: while |#A - #B| > 1, take
the weakest DPS from the larger team (last entry, since DPS list is sorted
desc) and move them to the smaller team. Picking the weakest minimises the
score-balance disruption — that DPS contributes the least to the score
gap, so moving them keeps DPS scores close.
Result for the same 20-man: 11/9 → 10/10. For a 19-man (1H + 17DPS) the
expected 10/9 stays 10/9 since gap is already 1. The earlier 'weakest
player fills the larger team for odd raids' contract still holds.
- Preview: show per-player ilvl/DPS suffix in team columns + tighten layout
- Team A/B title now includes the player count badge: 'Équipe A (5)'.
- After-stats block collapsed from 4 lines per team to 1: 'A: 5 (1T 0H 4DPS — DPS 200)'. HPS suffix only added when at least one team has heal data, so empty raids don't get noise. Matches the Before block's 2-line shape.
- Each team-list line now appends a grey suffix after the player name: '[ilvl 432]' when source = ILVL, or '[245.6k]' (k/M-formatted DPS) otherwise. Players see at a glance who's strongest on which side.
- fmtNum hoisted to module scope so both the Source preview and the team-column formatter share the same formatting.
- Empty-split branch resets the team titles to the bare label so the player count doesn't stick from a previous compute.
- Preview: tighten Team A/B columns
- Drop the redundant '[N players: T H DPS — score X]' line at the top of
each team list — the same info is shown in the 'After' stats block right
above the columns, so duplicating it just adds noise. - Bump role icons from 14 → 16 inside the listing so they read cleanly next
to the class-coloured name. - Two-space gap between icon and name (was one) for visual breathing.
- listFS width 300 → 320 to fit Name-Realm suffixes on EU/PvP realms without
early wrap. SetSpacing(4) between rows so multi-line lists don't feel
cramped. - listFS y offset from title BOTTOMLEFT 0,-6 → 0,-10 for a clearer header
separation.
- Drop the redundant '[N players: T H DPS — score X]' line at the top of
- CLAUDE.md: document the on-screen position clamp convention
Mirror the BossWatch CLAUDE.md note (lines 118-139 of u:\WoW_BossWatch\CLAUDE.md):
SetClampedToScreen(true) does not protect the initial SetPoint at load, so
saved coords from a different monitor / resolution need an explicit
UIParent:GetWidth/GetHeight comparison before being applied. Records the
pattern actually in use (restorePosition + the mirror in ShowOptionsAt) so
future persisted-position widgets follow the same recipe. - Off-screen window recovery: clamp saved position to current UIParent
If the user drags the panel on a 4K monitor and later launches WoW on a
1080p screen (or windowed mode at a smaller size), SetClampedToScreen alone
doesn't help — clamp only kicks in during drag/SetPoint, not for a
SetPoint(...) call with already-off-screen offsets at load.
restorePosition() now validates abs(x) <= UIParent.width and abs(y) <=
UIParent.height before applying. If either is exceeded, the saved position
is wiped from the DB and the panel falls back to CENTER. Same guard applied
to ShowOptionsAt (sister-addon handoff path) so a bad handoff doesn't lock
the panel off-screen.
Matches BossWatch's v0.7.3 behaviour. Documented in CHANGELOG under
[Unreleased]. - Add Item Level source (Blizzard inspect API, zero deps)
New 5th source 'Item Level (inspect)' wired into DPSSource:- ilvlQueue + ilvlBusy throttle: one NotifyInspect at a time, 1.5s between
inspects, 3s safety timeout if INSPECT_READY never fires (out of range etc). - INSPECT_READY handler resolves the GUID to a raid/party unit, reads
C_PaperDollInfo.GetInspectItemLevel(unit), caches the ilvl per name with
a 90s TTL, then ClearInspectPlayer + chains the next queue entry. - RefreshIlvl(): enqueue every raid/party member except self (own ilvl is
read directly via GetInspectItemLevel('player') / GetAverageItemLevel). - GetDPS and GetHPS both return the same cached ilvl when source='ILVL' —
it's a single character-power number used for both halves of the snake
distribution. - ListActors returns every cached entry so the Source preview shows what
the inspect sweep has gathered so far (trickles in over ~30s for a 20-man). - IsAvailable always true (no addon dependency, Blizzard API only).
- ActiveSourceLabel shows 'Item Level (inspect) — N cached'.
UI: Setup page gains a 'Scan raid ilvl' button next to the active-source
label. README + CHANGELOG callout the new source as the recommended
zero-dependency fallback when no damage meter is loaded.
User-facing: same as right-click → Inspect a player. Pure Blizzard API, no
'sniffing' beyond what every PvE addon already does.
- ilvlQueue + ilvlBusy throttle: one NotifyInspect at a time, 1.5s between
- README: GitHub-callout warning recommending Details!/Recount/Skada
Without a damage meter loaded, GetEffectiveWeight/GetEffectiveHPS fall back
to the Manual slider value (default 50). The split still computes, but it's
not informed by who actually deals/heals in your raid. Make this explicit at
the top of the README so users don't install bare and wonder why the
balance feels random. Details! recommended (most accurate combat parsing). - Add README.md, CHANGELOG.md (Keep a Changelog), MIT LICENSE
Pre-publish package — mirrors the BossWatch / TankWatch family layout. README
highlights the standalone (0 required addons) positioning, the sister-addon
family, the 10-40 man support range, and the optional Details/Recount/Skada
integrations. CHANGELOG documents v0.1.0 in Keep-a-Changelog format with the
combat-lockdown / built-in-tracker technical notes captured at the bottom. - Changelog: enforce '0 required addons' + sister-family convention
User-confirmed convention for the Timikana addon family (BossWatch, TankWatch,
SplitWatch, future siblings): every changelog batch must call out at the top
that the addon is standalone (0 required deps, optional integrations listed)
AND that it belongs to the sister-addon family.
v0.1.0 entry now leads with:- '0 required addons — works standalone. Details!/Recount/Skada optional.'
- 'Sister addon to BossWatch + TankWatch — shared side-tab nav + gold UI.'
Both lines translated in frFR. Also tweaked the damage-meter line to mention
that unavailable ones grey out (recently shipped feature).
- Bump max raid size to 40 (Classic Era ceiling)
Splitter:GetTargetGroups now caps perTeam at 4 — a WoW raid has 8 subgroups
total (1-8), so the maximum addressable team layout is groups 1-4 vs 5-8 =
20 vs 20. The math.min(4, ceil(N/5)) cap stops the helper from returning
target subgroups beyond 8 (which SetRaidSubgroup would reject).
Coverage:- 10-man → A=group 1, B=group 2
- 11-20 → A=1+2, B=3+4
- 21-30 → A=1+2+3, B=4+5+6
- 31-40 → A=1+2+3+4, B=5+6+7+8 (maxes out subgroups)
About + locale strings updated from '10-30 man' to '10-40 man'.
- Details!: use GetActorList instead of GetContainer for solo reads
GetContainer returns a structured object whose iteration (._ActorTable /
GetIterator) varies between Details! versions, so my pairs() walk over the
container was inconsistently surfacing actors in solo. Switch to
combat:GetActorList(attr), which always returns a plain array of actor
tables.
Also fall back to Details:GetCombat(1) (last completed combat) when the
current one is empty — needed so the preview still shows the player's
DPS/HPS between pulls.
Listing: drop only the synthetic [*] aggregate Details inserts at index 1
(name starts with '['); keep everything else (player, pets, environment)
so solo damage/heal lines are visible in the source preview. - Dropdown: grey out + disable unavailable sources
makeDropdown takes an optional availabilityFn(value)->bool. When provided and
returning false for an option:- the radio text gets a grey '(non installé)' suffix
- the onClick handler refuses to update the DB
- if the descriptor supports SetEnabled, it's disabled (further suppresses click)
Wired to the DPS source dropdown so Details!/Recount/Skada are visibly
unselectable when the corresponding addon isn't loaded. Manual stays always
available.
- Pages: leave room for the outer scrollbar by trimming widget widths
Two text widgets had no SetWidth so they rendered on a single overflowing line
that the outer ScrollFrame scrollbar then visually clipped:- previewEmpty ('Pas de données — ...') on the Source preview section.
- row_empty ('Aucun membre de raid détecté ...') on the Joueurs page.
Both now SetWidth(560) + SetJustifyH('LEFT') so they wrap cleanly.
Everything that was 640px wide (hint texts, status lines, mode FS, warnings,
banner, slash-cmd list, perm status FS, inner Weights scroll, source-preview
scroll) is now 600px, and inner scroll content/rows shrink from 620 to 580.
This keeps content well clear of the UIPanelScrollFrameTemplate scrollbar
that lives on the right edge of every page.
- UI polish: test-toggle label flips, team separator, scrollbar fix, role icons, Players tab
- Test-mode button text now flips between 'Activer le mode test' / 'Désactiver le mode test' on click (Preview + Weights pages). Preview's parent.refresh syncs the label so toggling from one page is reflected on the other.
- Add a vertical gold separator between Team A and Team B columns on the Preview page (1px gradient, y=-200 to y=-450).
- Stop forcing min content height to 800 in makePage — use max(viewport, naturalSpan) instead. The outer Blizzard scrollbar now stays hidden when nothing overflows (was double-stacking with the inner Weights scrollbar).
- Weights rows: role icon moves BEFORE the name (was sandwiched between name and slider) and the icon size bumps from 14px to 20px via a new size arg on roleIcon().
- Rename tab 'Poids' to 'Joueurs' (FR) — the source key changes from L['Weights'] to L['Players'] so future locales translate accordingly.
- Pages: wrap in ScrollFrame, kill BOTTOMLEFT anchors
Scrolling:- Each tab page is now a UIPanelScrollFrameTemplate ScrollFrame with a content
child, mirroring BossWatch. Page builders receive the content frame as their
parent, so widgets sit on a scrollable canvas. Long pages (Setup with 4
chained sections, About with the expanded changelog, Preview with 20-30 man
team lists, Weights with the per-player slider list) all get a Blizzard
scrollbar when content exceeds the viewport. - After build, content height is sized to cover the lowest section's bottom +
24px padding (deferred 50ms so anchors resolve). - Setup-page auto-refresh ticker now hooks the ScrollFrame's OnShow/OnHide
instead of the content frame (OnShow on a frame inside a ScrollFrame doesn't
fire when the SF is shown/hidden).
Overlap fixes — every BOTTOMLEFT anchor on a page-level widget was breaking
because _captureAndReparent rebound them to the section container's bottom,
which is itself derived from children GetBottom (circular sizing). Converted
to fixed-Y TOPLEFT anchors: - Preview warnings line: was BOTTOMLEFT 14,14 → TOPLEFT 14,-460 (below team
columns, scrolls if needed for 30-man). - Weights inner scroll: was BOTTOMRIGHT-relative → fixed 640x360.
- Weights action buttons (Reset / Refresh / Toggle test): were BOTTOMLEFT
14,14 + LEFT-chained → TOPLEFT 14,-428 / 182,-428 / 350,-428. - Setup Classic banner: was BOTTOMLEFT 14,14 → TOPLEFT 14,-580.
- Each tab page is now a UIPanelScrollFrameTemplate ScrollFrame with a content
- Sections: chained containers — collapsing one reflows everything below
BossWatch-style section chain:- makeSection now builds a Frame container that anchors to the previous
section's BOTTOMLEFT/BOTTOMRIGHT (so consecutive sections stack vertically
with a fixed gap). The first section on a page uses its passed (x, y) as
the anchor; subsequent sections ignore (x, y) and just chain. - Container TOPRIGHT pins to parent TOPRIGHT, so every section is full-width
(no more cramped left/right columns on the Setup page). - _captureAndReparent: when a widget registers, it gets reparented onto the
container and its anchors translated from page-relative-Y to container-
relative-Y (page_y - section._originY). When the container's height shrinks,
the widget moves with it. - SetCollapsed sets container height to COLLAPSED_HEIGHT (22) or natural span.
UpdateNaturalHeight scans children's GetBottom and sizes the container to fit.
Deferred via C_Timer.After(0) so widgets that register after the call get
picked up. - Setup page reordered as single full-width column: General → DPS source →
Source preview → Permission status. Permission status no longer lives in
the right column. - About page reflowed: header block (logo + title) unchanged, then chained
Slash commands → Panel (opacity slider + reset window button side-by-side)
→ Changelog.
Net result: collapsing the General section moves DPS source and everything
below it up by the height difference. Same for any section on any page.
- makeSection now builds a Frame container that anchors to the previous
- About page: BossWatch-style layout (logo + 2 columns + changelog)
- Logo (120x120) top-left as visual anchor.
- Right of logo: title 'SplitWatch vX.Y.Z', subtitle, author, slash command + alias, sister-addons line.
- Left column at y=-160: 'Slash commands' section listing /splitw, /splitw preview, /splitw apply, /splitw test, /splitw reset (each in yellow).
- Right column at y=-160: 'Panel' section with opacity slider + 'Reset window position' button.
- Full-width below: Changelog with expanded v0.1.0 entries (damage meters, HPS heal balancing, 10-30 raid support, collapsible sections).
- Source preview: filter nameless actors from meter fallback
Details!/Recount/Skada containers can include entries without a usable string
name (pets, environment actors, or otherwise-broken rows in the meter's data).
Pushing those into the preview list crashes nameFS:SetText with 'bad argument #1'.
Filter to type(a.name) == 'string' before adding, and default to '?' as a final
guard in the row builder. - Source preview: list actors from Details/Recount/Skada when roster is empty
Adds DPSSource:ListActors() that enumerates everyone the active meter has data
for — walks Details GetContainer(1)+(2), Recount's Fight table, or Skada's
players list — and returns name/class/dps/hps tuples. The Setup-page preview
now falls back to that list when SplitW.Roster:Scan() returns no members, so
solo players can still verify their damage meter is hooked up and the
DPS/HPS values are flowing.
Roster path is unchanged; it stays preferred since it provides accurate role
icons + class colors. The fallback skips role icons (everyone defaults to
DAMAGER) but keeps class coloring and the raw numbers. - Drop built-in combat-log tracker — keep Details!/Recount/Skada/Manual
pcall does not suppress ADDON_ACTION_FORBIDDEN because that's a UI event fired
by Blizzard's taint system, not a Lua error — BugGrabber still reports it. The
root cause of why SplitWatch specifically can't register COMBAT_LOG_EVENT_UNFILTERED
(while Details!/Recount/Skada/BigWigs all can) is undiagnosed; deferring the
registration to PLAYER_LOGIN doesn't help either.
Pragmatic resolution: stop registering the event at all. DPSSource._builtinAvailable
stays false, the tracker frame is created but has no events wired, the OnEvent
handler never fires, and getDPSFromBuiltin/getHPSFromBuiltin always return nil.
Remove the 'Built-in (combat log)' option from the source dropdown so users don't
land on a dead option. Their saved-DB BUILTIN value still works (returns nil →
falls back to manual weight), but the picker only offers Details!/Recount/Skada/Manual. - Fix Source Preview overlap with Permissions + harden COMBAT_LOG registration
Layout fix:- Move Source preview from y=-250 to y=-340 so it no longer overlaps with the
right-column Permission Status section at y=-250 (the source preview was using
full width 640, which crossed into the right column at x=360).
Event registration hardening: - Wrap clf:RegisterEvent calls in pcall to survive WoW 12.0's
ADDON_ACTION_FORBIDDEN on COMBAT_LOG_EVENT_UNFILTERED (cause unclear — other
damage meters succeed, but ours triggers Blizzard's taint check). Without the
wrap the error was firing 6× on load and the addon never finished initialising. - Track DPSSource._builtinAvailable and surface 'Built-in (blocked by Blizzard
event protection)' in the Active source line when registration failed, so the
user knows why the live DPS numbers stay at —. - Change default dpsSource from BUILTIN to DETAILS so a fresh install doesn't
land on the broken source. Built-in stays in the dropdown for users who want
to retry it.
- Move Source preview from y=-250 to y=-340 so it no longer overlaps with the
- Sections: fix click area + register free-floating widgets
Two bugs causing collapse to look broken:- Click area was 30x20 only — header:GetStringWidth() returns 0 at frame-build
time (FontString not yet measured), and Lua's '0 or 100' evaluates to 0 since
0 is truthy. So the area only covered the first ~3 characters of the header.
Fixed by switching to two SetPoints (TOPLEFT + BOTTOMRIGHT) so the area
spans the full section-line width minus the reset button slot, regardless of
the FontString's measured size. Also bumped frame level above siblings. - Many widgets (hint FontStrings, ScrollFrame previews, stats lines, team-column
list FontStrings, changelog entries, warning line, alpha slider) were created
directly via CreateFontString/CreateFrame and never passed through the widget
factories, so they weren't tracked in _currentSection.children — collapse hid
nothing visible. Explicit _registerInSection() calls added everywhere a free-
floating widget exists, on all four pages.
- Click area was 30x20 only — header:GetStringWidth() returns 0 at frame-build
- Panel: collapsible sections + per-section reset (BW parity)
- Replace makeHeader with makeSection: each section has a click area on the
header (toggle collapse), a chevron texture (UI-PlusButton-Up/UI-MinusButton-Up),
and a reset button (UI-RefreshButton) that resets only the dbKeys registered
in that section to SplitW.Defaults. - Widget factories (makeCheck/makeSlider/makeDropdown/makeButton/makeLabel) push
themselves and their dbKey into _currentSection so collapse hides them and
reset wipes their values. - Collapsed state persists in SplitWatchDB.collapsedSections keyed per section
(setup.general, setup.dps_source, setup.source_preview, setup.permissions,
weights.main, preview.main, about.info, about.panel, about.changelog). - Phase 1 fix: Preview-page status FontString moved to its own row (y=-68, full
width) so 'Pas de raid détecté — active le mode test pour visualiser' no longer
overflows off-screen. Before/After labels and team columns pushed down to fit. - Phase 3: panel-opacity slider moved from Setup (right column) to About (right
column), since it's a cosmetic/window pref, not a per-character setting.
- Replace makeHeader with makeSection: each section has a click area on the
- Setup page: live DPS/HPS preview of the active source
Adds a scrollable list under the source dropdown showing each roster member with the current DPS and HPS readings from the selected source. Updates every 1.5s while the Setup tab is visible (cancelled on hide) and on dropdown change via the shared refresh hook. Numbers formatted as k/M for readability; dash for no data. Moves Permission status to the right column to make room. - Support 10-30 man raids + HPS-based heal balancing + built-in meter
Algorithm:- Dynamic team→subgroup mapping in Splitter:GetTargetGroups: 10-man uses groups 1 vs 2, 11-20 uses 1+2 vs 3+4, 21-30 uses 1+2+3 vs 4+5+6.
- Healers no longer alternate by count — they snake-distribute by HPS (greedy: weakest healer goes to the lower-throughput team). Matches the DPS algorithm so weak/strong asymmetry filters into both roles.
- Compute() now returns healScoreA/healScoreB alongside scoreA/scoreB.
- Drop UNEVEN_25 warning (raid sizes >20 now handled natively); add UNEVEN_TEAMS info warning when team counts differ by more than 1.
DPS / HPS sources: - Add built-in combat-log tracker (parses COMBAT_LOG_EVENT_UNFILTERED, sums damage + effective healing per source name, snapshots on PLAYER_REGEN_ENABLED). Zero addon dependency.
- Add Skada alongside Details!/Recount; each meter now exposes both DPS and HPS.
- New default = BUILTIN so the addon works out of the box without Details!/Recount/Skada installed.
- Panel: source dropdown lists all 5 (Built-in, Details!, Recount, Skada, Manual) with a single localised tooltip.
- Preview shows per-team DPS + HPS scores so the user can see both balances.
Note: PR description-grade summary kept here intentionally because the surface area touched is large.
- Preview: surface test-mode button + roster status line
When the user isn't in a raid the roster scan returns 0 members and the preview shows empty teams with no clue why. Add a 'Toggle test mode' button on the Preview page (was only on Weights) and a status line that says 'no raid detected — enable test mode' / 'live roster (N members)' / 'test mode ON' so the empty-state is no longer mysterious. - Panel: clear bottom-tabs strip + fix missing glyphs
- Move pageHolder.BOTTOMRIGHT from y=8 to y=32 so docked bottom tabs aren't visually clipped by page content (BW gets away with 8 because its pages are scrollable).
- Replace unicode → arrow (U+2192) and ⚠ warning (U+26A0) with Blizzard texture inlines — FRIZQT__ doesn't include those glyphs and renders them as empty boxes.
- Panel UI: match BossWatch look — bottom tabs, alpha slider, TGA portrait
- Switch bottom tabs from PanelTopTabButtonTemplate to PanelTabButtonTemplate (mirrors BossWatch).
- Add multi-row tab wrap layout so narrow panels stack tabs cleanly.
- Apply panel:SetAlpha (0.85 default) + opacity slider on Setup page, account-wide DB key.
- Convert logo.png to logo.tga (WoW textures need TGA/BLP; PNG paths render as empty squares).
- Set portrait via panel.portrait and panel.PortraitContainer.portrait (covers both PortraitFrameTemplate variants).
- Side-tab icons now reference .tga explicitly (Media/logo.tga for self + BossWatch sister).
- pageHolder bounds match BossWatch (8,-60 / -8,8).
- Initial v0.1.0 — MVP manual weights mode
- Roster scan (real raid + simulated 20-man test mode)
- Snake-distribution algorithm: tanks alternate, healers alternate, DPS by descending weight greedy
- Apply.lua: permission-gated SetRaidSubgroup queue with combat-lockdown deferral
- DPSSource.lua: Details! and Recount fallbacks (manual is the only active source for v0.1.0)
- Options panel: Setup / Weights / Preview (before+after stats) / About+Changelog
- Side tabs to BossWatch + TankWatch (cross-addon panel handoff)
- Minimap launcher, Blizzard Settings host, /splitw + /splitwatch slash
- frFR locale at parity with enUS
- Multi-toc: SplitWatch.toc (retail 12.x) + SplitWatch-Mists.toc (MoP Classic 5.5)

