Desktop companions: settings tooltips back in Qt, added to Win32 and Cocoa

Tatsuya79: tooltips in the Qt settings dialog stopped working; only
Video > Video Filters and a few achievement rows still had one.

Cause: d636ba135c / f5c0413682 turned most sublabels into a table.
menu_cbs_init_bind_sublabel() now stores the message in
cbs->sublabel_enum and binds action_bind_sublabel_from_enum(), which
reads it back through file_list_get_actiondata_at_offset(list, i). The
Qt dialog has no list - it always called action_sublabel() with NULL -
so every table-driven sublabel came back empty, and only the entries
that still have a function (video filter, the cheevos rows) kept
their tooltip.

menu_cbs_sublabel_for_enum() is the list-free entry point: it binds,
reads sublabel_enum when the sublabel is data, and calls the function
when it is code. add_sublabel_and_whats_this() uses it; every setting
row in the Qt dialog has its tooltip again.

The View > Options rows (the small desktop-menu settings the Qt, Win32
and Cocoa companions all render) never had help text at all. Thirteen
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_* messages are added, served
through companion_core_setting_sublabel(), and shown as tooltips on
all three: Qt sets them on each control and its form label, the Win32
options list gets LVS_EX_INFOTIP with an LVN_GETINFOTIP handler, and
the Cocoa options table answers tableView:toolTipForCell:.

Checked: Qt6 build of the tree, tools/companion_qt_persist_test.sh,
tools/companion_win32_test.sh under Wine, tools/companion_cocoa_test.sh
under GNUstep, tools/companion_core_test.sh (new: every row has its
own help message), mingw_syntax_check on the C files. Visual check of
the tooltips themselves on Windows and macOS still needed.
This commit is contained in:
libretroadmin committed 2026-09-10 21:35:18 +02:00
1 parent 6b7bb78ec7
commit 9eaa3750bd
10 files changed
+196 -9

No files matched your search

+52
View File
@@ -30277,6 +30277,58 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY,
"Remember window geometry:"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY,
"Restore the desktop menu window to the position and size it had when RetroArch last quit."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB,
"Open the content browser on the tab that was selected when RetroArch last quit."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THEME,
"Colour theme of the desktop menu: follow the system, use the built-in dark theme, or load a custom stylesheet."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES,
"List hidden files and folders in the file browser."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR,
"Colour used to highlight the selected row, as #rrggbb."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST,
"When a core is already loaded, offer it first when starting content."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST,
"Playlist to show when the desktop menu opens. Leave empty for the first one."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT,
"Memory kept for decoded thumbnails, in megabytes. Larger values scroll big playlists more smoothly."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT,
"Largest edge, in pixels, an image dropped onto a thumbnail is scaled down to before saving. 0 keeps the original size."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_CUSTOM_THEME,
"Stylesheet file used when the theme is set to Custom."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT,
"Most entries the All Playlists view shows in list mode. 0 shows every entry."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT,
"Most entries the All Playlists view shows in grid mode. 0 shows every entry."
)
MSG_HASH(
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SCAN_FINISH_CONFIRM,
"Show a message when a content scan finishes."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB,
"Remember last content browser tab:"
+22
View File
@@ -1433,6 +1433,28 @@ static int action_bind_sublabel_from_enum(
return 1;
}
size_t menu_cbs_sublabel_for_enum(enum msg_hash_enums enum_idx,
unsigned type, size_t size, char *s, size_t len)
{
menu_file_list_cbs_t cbs;
if (!s || !len)
return 0;
s[0] = '\0';
memset(&cbs, 0, sizeof(cbs));
cbs.enum_idx = enum_idx;
cbs.sublabel_enum = MSG_UNKNOWN;
menu_cbs_init_bind_sublabel(&cbs, NULL, NULL, 0, type, size);
/* Table-driven: the bound callback reads sublabel_enum back out of
* the list's action data, which a caller without a list cannot
* supply, so read it here. This is what went missing for the
* desktop companions' tooltips when the sublabels became data. */
if (cbs.sublabel_enum != MSG_UNKNOWN)
return strlcpy(s, msg_hash_to_str(cbs.sublabel_enum), len);
if (cbs.action_sublabel && cbs.action_sublabel != action_bind_sublabel_from_enum)
cbs.action_sublabel(NULL, type, 0, NULL, NULL, s, len);
return strlen(s);
}
int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
const char *path,
const char *label, size_t lbl_len,
+9
View File
@@ -317,6 +317,15 @@ int menu_cbs_init_bind_get_string_representation(menu_file_list_cbs_t *cbs,
int menu_cbs_init_bind_label(menu_file_list_cbs_t *cbs,
const char *path, const char *label, unsigned type, size_t idx);
/* The sublabel a menu entry with this enum would show, for a caller
* that has no file list: the desktop companions use it for tooltips
* on settings widgets. Resolves table-driven sublabels (which the bound
* callback can only read back through a list) and function-driven
* ones that do not need the list. Returns the length written, 0 when
* the entry has none. */
size_t menu_cbs_sublabel_for_enum(enum msg_hash_enums enum_idx,
unsigned type, size_t size, char *s, size_t len);
int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
const char *path, const char *label, size_t lbl_len,
unsigned type, size_t idx);
+15
View File
@@ -32222,6 +32222,21 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_TYPE,
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT,
MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT,
/* Tooltips for the desktop companion's View > Options rows; shared
* by the Qt, Win32 and Cocoa companions through companion_core. */
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THEME,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_CUSTOM_THEME,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SCAN_FINISH_CONFIRM,
MENU_ENUM_LABEL_VALUE_QT_MENU_TOOLS,
MENU_ENUM_LABEL_VALUE_QT_MENU_HELP,
MENU_ENUM_LABEL_VALUE_QT_MENU_DOCK_CONTENT_BROWSER,
+21
View File
@@ -435,6 +435,27 @@ const char *companion_core_setting_label(companion_core_t *core, size_t i)
return i < CS_COUNT ? cs_rows[i].label : "";
}
const char *companion_core_setting_sublabel(companion_core_t *core, size_t i)
{
static const enum msg_hash_enums cs_help[CS_COUNT] = {
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THEME,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_CUSTOM_THEME,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_LIST_MAX_COUNT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_ALL_PLAYLISTS_GRID_MAX_COUNT,
MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SCAN_FINISH_CONFIRM,
};
(void)core;
return i < CS_COUNT ? msg_hash_to_str(cs_help[i]) : "";
}
enum companion_setting_kind companion_core_setting_kind(companion_core_t *core, size_t i)
{
(void)core;
+2
View File
@@ -513,6 +513,8 @@ enum companion_setting_kind
};
size_t companion_core_setting_count(companion_core_t *core);
const char *companion_core_setting_label(companion_core_t *core, size_t i);
/* One-line help for row @i, for a tooltip; "" for a row without one. */
const char *companion_core_setting_sublabel(companion_core_t *core, size_t i);
enum companion_setting_kind companion_core_setting_kind(companion_core_t *core, size_t i);
/* Current value as text into @s; returns @s. */
const char *companion_core_setting_get(companion_core_t *core, size_t i, char *s, size_t len);
+19
View File
@@ -834,6 +834,25 @@ static void test_settings_table(void)
CHECK(n == 13, "13 rows (got %u)", (unsigned)n);
for (i = 0; i < n; i++)
CHECK(*companion_core_setting_label(c, i) && *companion_core_setting_get(c, i, buf, sizeof(buf)) != 2, "row %u has a label", (unsigned)i);
/* Tooltip help: every row has its own message, none shared (the
* stub returns a distinct string per enum, so two rows on one
* enum would collide). */
{
char help[32][64];
size_t j;
CHECK(n <= 32, "settings table fits the help check");
for (i = 0; i < n && i < 32; i++)
{
const char *h = companion_core_setting_sublabel(c, i);
CHECK(h && *h, "row %u has tooltip help", (unsigned)i);
strlcpy(help[i], h ? h : "", sizeof(help[i]));
}
for (i = 0; i < n && i < 32; i++)
for (j = 0; j < i; j++)
CHECK(!string_is_equal(help[i], help[j]),
"rows %u and %u share help", (unsigned)i, (unsigned)j);
}
CHECK(!*companion_core_setting_sublabel(c, n), "out-of-range row has no help");
CHECK(companion_core_setting_kind(c, 2) == COMPANION_SETTING_CHOICE && companion_core_setting_choice_count(c, 2) == 3, "theme is a 3-way choice");
CHECK(companion_core_setting_set(c, 2, "Dark") && test_settings.uints.desktop_menu_theme == 1, "theme by label");
CHECK(companion_core_setting_set(c, 2, "2") && test_settings.uints.desktop_menu_theme == 2, "theme by index");
+15
View File
@@ -2523,6 +2523,21 @@ static void cc_thumb_done(void *ud, const char *path, int w, int h,
return row;
}
/* Hover help for View > Options rows: the same one-line text the Qt
* dialog and the Win32 companion show. NSTableView asks its delegate
* per cell; every other table has no help and gets nil. */
- (NSString*)tableView:(NSTableView*)tv toolTipForCell:(NSCell*)cell
rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)col
row:(NSInteger)row mouseLocation:(NSPoint)loc
{
const char *help;
(void)cell; (void)rect; (void)col; (void)loc;
if (!wimp || tv != setTable || row < 0)
return nil;
help = companion_core_setting_sublabel(wimp->core, (size_t)row);
return (help && *help) ? [NSString stringWithUTF8String:help] : nil;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tv
{
if (!wimp)
+27 -9
View File
@@ -106,18 +106,12 @@ static const QRegularExpression decimalsRegex("%.(\\d)f");
static inline void add_sublabel_and_whats_this(
QWidget *widget, rarch_setting_t *setting)
{
struct menu_file_list_cbs cbs = {};
char tmp[512];
tmp[0] = '\0';
cbs.enum_idx = (enum msg_hash_enums)setting->enum_idx;
menu_cbs_init_bind_sublabel(&cbs, NULL, NULL, 0,
(unsigned)setting->type, setting->size);
cbs.action_sublabel(0, 0, 0, 0, 0, tmp, sizeof(tmp));
widget->setToolTip(tmp);
if (menu_cbs_sublabel_for_enum((enum msg_hash_enums)setting->enum_idx,
(unsigned)setting->type, setting->size, tmp, sizeof(tmp)))
widget->setToolTip(tmp);
msg_hash_get_help_enum((enum msg_hash_enums)setting->enum_idx,
tmp, sizeof(tmp));
@@ -2657,6 +2651,30 @@ ViewOptionsWidget::ViewOptionsWidget(MainWindow *mainwindow, QWidget *parent) :
form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_MENU_VIEW_OPTIONS_THEME), m_themeComboBox);
form->addRow(m_highlightColorLabel, m_highlightColorPushButton);
/* The same one-line help the Win32 and Cocoa companions show for
* these rows, on both the label and the control. */
{
struct { QWidget *w; enum msg_hash_enums help; } tips[] = {
{ m_saveGeometryCheckBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_GEOMETRY },
{ m_saveLastTabCheckBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SAVE_LAST_TAB },
{ m_showHiddenFilesCheckBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SHOW_HIDDEN_FILES },
{ m_suggestLoadedCoreFirstCheckBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_SUGGEST_LOADED_CORE_FIRST },
{ m_startupPlaylistComboBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_STARTUP_PLAYLIST },
{ m_thumbnailCacheSpinBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_CACHE_LIMIT },
{ m_thumbnailDropSizeSpinBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THUMBNAIL_DROP_SIZE_LIMIT },
{ m_themeComboBox, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_THEME },
{ m_highlightColorPushButton, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR },
{ m_highlightColorLabel, MENU_ENUM_SUBLABEL_QT_MENU_VIEW_OPTIONS_HIGHLIGHT_COLOR },
};
for (size_t i = 0; i < sizeof(tips) / sizeof(tips[0]); i++)
{
const char *tip = msg_hash_to_str(tips[i].help);
tips[i].w->setToolTip(tip);
if (QWidget *label = form->labelForField(tips[i].w))
label->setToolTip(tip);
}
}
layout->addLayout(form);
layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
+14
View File
@@ -3118,6 +3118,17 @@ static LRESULT CALLBACK cw_set_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARA
if (w && ((NMHDR*)lparam)->idFrom == IDC_CW_SET_LIST)
{
NMHDR *hdr = (NMHDR*)lparam;
if (hdr->code == LVN_GETINFOTIPA)
{
/* The tooltip for the hovered row: the same one-line help
* the Qt dialog shows. */
NMLVGETINFOTIPA *tip = (NMLVGETINFOTIPA*)lparam;
const char *help = companion_core_setting_sublabel(w->core,
(size_t)tip->iItem);
if (tip->pszText && tip->cchTextMax > 0 && help && *help)
strlcpy(tip->pszText, help, (size_t)tip->cchTextMax);
return 0;
}
if (hdr->code == NM_DBLCLK || hdr->code == NM_RETURN)
{
int sel = (int)SendMessageA(w->set_list, LVM_GETNEXTITEM, (WPARAM)-1, MAKELPARAM(LVNI_SELECTED, 0));
@@ -3152,6 +3163,9 @@ static void cw_set_show(ui_companion_win32_wimp_t *w)
return;
cw_table_column(w, w->set_list, 0, "Setting", 330);
cw_table_column(w, w->set_list, 1, "Value", 260);
/* Hover help per row, served from LVN_GETINFOTIP below. */
SendMessageA(w->set_list, LVM_SETEXTENDEDLISTVIEWSTYLE,
LVS_EX_INFOTIP, LVS_EX_INFOTIP);
w->set_edit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL,
0, 0, 0, 0, w->set_hwnd, (HMENU)IDC_CW_SET_EDIT, inst, NULL);