feat(entry/stats/awards): Alt+W clear, slot drill-down, DXCC prefix column
Five operator-requested items: - Alt+W clears the QSO entry. Handled before the `typing` guard and above the keyer's key routing, so there is always one key that clears whatever else is running — Esc is not that key when the CW keyer reserves it. - The Grid box no longer pops outside the entry panel on a narrow window. Row 2 needed 300+130+76+gaps = 538 px inside a panel whose min-width is 520, so Grid was pushed out and clipped at every narrow width, not just extreme ones. QTH's min-width drops to 80 and the row wraps rather than overflowing if it ever still can't fit. - Selecting a QSO in the log now drives the Stats (F1) matrix. Uses its own WorkedBefore call into separate state, NOT runWorkedBefore: that one owns the entry form's wbRef and can trigger a field backfill, which browsing the log must never do. The entry form wins whenever it holds a call. - Clicking a coloured band/mode square lists the contacts behind it. Returns the exact callsign AND the rest of the entity, because that pair is what the cell's colour encodes; the call's own QSOs are bolded. The DXCC arm matches the stored dxcc column only — reconstructing it from the callsign here would disagree with the matrix above, which is built from that column. - The Awards DXCC list shows each entity's primary prefix in its own sortable column. Derived live from cty.dat into Ref.Group rather than stored on the reference row, so an existing installation needs no re-seed.
This commit is contained in:
@@ -3629,6 +3629,29 @@ func (a *App) computeAwardsForMode(defs []award.Def, modeClass string) ([]award.
|
||||
}
|
||||
refMetas := a.awardRefMetas(defs)
|
||||
results := award.Compute(defs, all, refMetas, nameOf)
|
||||
// DXCC: fill each reference's Group with the entity's primary prefix (XE,
|
||||
// DL, F…). Sorting/searching a 340-row list by bare entity number is
|
||||
// hopeless — the prefix is how operators actually identify an entity.
|
||||
// Derived from the live cty.dat rather than stored on the reference row, so
|
||||
// it needs no re-seed of an existing installation.
|
||||
if a.dxcc != nil {
|
||||
var pfx map[int]string
|
||||
for i := range results {
|
||||
if !strings.EqualFold(results[i].Code, "DXCC") {
|
||||
continue
|
||||
}
|
||||
if pfx == nil {
|
||||
if pfx = a.dxcc.PrefixByDXCC(); pfx == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
for j := range results[i].Refs {
|
||||
if n, err := strconv.Atoi(results[i].Refs[j].Ref); err == nil {
|
||||
results[i].Refs[j].Group = pfx[n]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Dynamic awards (POTA/SOTA/…) aren't fully loaded into the engine — their
|
||||
// list can be huge. Enrich them after the fact: real Total from the stored
|
||||
// count, and reference names for the worked references only.
|
||||
@@ -6054,6 +6077,38 @@ func (a *App) WorkedBefore(callsign string, dxccHint int) (qso.WorkedBefore, err
|
||||
return wb, err
|
||||
}
|
||||
|
||||
// BandSlotQSOs lists the contacts behind ONE cell of the entry Stats (F1)
|
||||
// matrix — "everything I have on 20m CW with this entity". Same drill-down the
|
||||
// Awards grid offers, for the panel an operator actually stares at while
|
||||
// working a station.
|
||||
//
|
||||
// modeClass is the matrix column class ("PH", "CW", "DIG"); empty means all.
|
||||
// Both the exact callsign and the entity are returned: a cell is amber for the
|
||||
// entity and green for the call, and the useful answer to "who gave me this
|
||||
// slot?" is the whole list.
|
||||
func (a *App) BandSlotQSOs(callsign string, dxccNum int, band, modeClass string) ([]qso.QSO, error) {
|
||||
if a.qso == nil {
|
||||
return nil, fmt.Errorf("db not initialized")
|
||||
}
|
||||
all, err := a.qso.BandSlotQSOs(a.ctx, callsign, dxccNum, band)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// "PH"/"DIG" are the matrix's column labels; award.ModeClass speaks
|
||||
// "PHONE"/"DIGI". Translate rather than teach one of them the other's names.
|
||||
want := map[string]string{"PH": "PHONE", "CW": "CW", "DIG": "DIGI"}[strings.ToUpper(strings.TrimSpace(modeClass))]
|
||||
if want == "" {
|
||||
return all, nil
|
||||
}
|
||||
out := make([]qso.QSO, 0, len(all))
|
||||
for _, q := range all {
|
||||
if award.ModeClass(q.Mode) == want {
|
||||
out = append(out, q)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// SetCompactMode toggles a tiny always-on-top window that exposes just the
|
||||
// QSO entry — useful when running on a single screen alongside WSJT-X,
|
||||
// JT-Alert or the cluster.
|
||||
|
||||
Reference in New Issue
Block a user