Quick hide already-known files filter in search results
Problem¶
Search results color-code files the user already has (downloading, shared, previously downloaded/"known", cancelled) but there is no way to hide them. On a busy search the rows you already have bury the new ones. Neither beba nor eMuleAI offers this — they only tint known rows — so this is a new eMuleBB affordance.
Decision / scope¶
- Add checkable Hide from results ▸ Shared / Downloading / Downloaded / Cancelled
toggles to the existing results filter box (the magnifier
▾dropdown), not a new toolbar. Default shows everything; the user opts in to hiding. - The filter predicate classifies each row's known-state from the same
download-queue / shared-files / known-files hash lookups the row colouring already
uses, so it does not depend on paint-time
m_eKnown. - State persisted as a
CPreferencesbitmask; toggling re-filters the active tab immediately. No eD2K/Kad wire change; presentation + preferences only.
Key files¶
srchybrid\SearchListCtrl.cpp(ResolveSearchKnownTypehelper,GetSearchItemColor,IsFilteredOut,AddResult),srchybrid\Preferences.h/.cpp(m_uSearchHideKnownStates),srchybrid\EditDelayed.h/.cpp(generic opt-in menu extension),srchybrid\SearchResultsWnd.h/.cpp(submenu + toggle handling + re-filter),srchybrid\MenuCmds.h,srchybrid\UserMsgs.h,srchybrid\emule.rc+ 43lang\*.rc.
Acceptance criteria¶
- Filter-box dropdown shows a "Hide from results" submenu with four checkable states; toggling hides/shows matching rows in the active search and updates the count; column-filter selection and text filtering still work.
- Hidden-state choice persists across restart; default is show-all (no behaviour change when unset).
- Other filter boxes (downloads, shared files) are unaffected by the new menu.
- New
IDS_SEARCH_HIDE_FROM_RESULTSlabel present in all 43 stock languages;rc-localization-preflight.pygreen. - Debug|x64, Release|x64, Release|x64 diagnostics build clean; native + python
suites pass;
validategreen.
Outcome (2026-06-11)¶
SearchListCtrl.cpp:ResolveSearchKnownTypefactored out ofGetSearchItemColorand reused byIsFilteredOut;AddResultnow always consults the filter; tab header count reflects the hide mask. Shared flagsESearchKnownHideFlags+SearchKnownHideFlag()live inSearchFile.h.- Preference
m_uSearchHideKnownStates(uint8 bitmask) added toPreferences.h/.cpp(ini keySearchHideKnownStates, default 0); registered in the build-tests preference inventory + regenerated schema manifest. CEditDelayedgained an opt-inSetAllowOwnerMenuExtension; raisesUM_FILTER_MENU_EXTENDso the owner can append items and forwards foreign menu commands to the parent.SearchResultsWndenables it, builds the "Hide from results" submenu, toggles the bits, and re-filters viaReapplyActiveResultFilter.- Localization:
IDS_SEARCH_HIDE_FROM_RESULTSadded toemule.rc+ all 43 stock languages; state items reuse existingIDS_SHARED/DOWNLOADING/DOWNLOADED/CANCELLED. - Verification: 3 x64 builds clean; native doctest + python (1333) suites pass;
validate+rc-localization-preflight.pygreen.
Follow-up (2026-06-11)¶
Operator review: the dropdown must be one level (no flyout submenu) and the
states single-select, not independent checkboxes. Reworked to a flat radio group
appended directly to the filter dropdown — Known / Downloaded / Shared /
Downloaded/Shared / No filter (default) — where Known hides all known states
and Downloaded/Shared hides both. Added IDS_SEARCH_HIDE_NO_FILTER ("No filter")
across all 43 languages; the "Downloaded/Shared" label is composed from the existing
IDS_DOWNLOADED/IDS_SHARED strings.
Root cause of "filtering didn't work": the hide-command id block started at
MP_FILTERCOLUMNS + 50 (11350), but CEditDelayed::OnCommand claimed
<= MP_FILTERCOLUMNS + 50 as a filter-column selection, so the boundary hide id was
swallowed instead of forwarded to the parent. Moved the block clear to 11400 and
corrected the off-by-one bound to < MP_FILTERCOLUMNS + 50.