Skip to content

Conversation

@Warchamp7
Copy link
Member

@Warchamp7 Warchamp7 commented Apr 20, 2025

Description

Replaces the add source context menu with a brand new window.

  • Adds new FlowFrame and FlowLayout for automatic wrapping widget frame

    • Supports keyboard navigation of focusable widgets using arrow keys
  • Adds ThumbnailManager class

    • Keeps a cache of low resolution thumbnails of all visible sources
    • Periodically updates the oldest preview thumbnail among visible sources only
    • Utilizes ScreenshotObj which performs output over several render ticks
    • Throttled update loop
  • Adds new dialog for adding sources

    • Shows static previews of sources when possible
    • Supports selection of multiple existing sources in the list via Ctrl and/or Shift + clicking
    • Supports keyboard navigation of the existing source list
    • Supports drag and drop of individual sources onto the main window without closing the dialog

Sources Dock Menu

image

New Window

image
obs64_E0SOtuhy93.mp4

Motivation and Context

The current process for adding a source is rather cumbersome, especially when adding a source that already exists. Ideally users should be re-using Sources whenever it makes sense, so one of the goals of this PR is exposing that better than the old radio button and list selection.

How Has This Been Tested?

Created a number of different sources.

Types of changes

  • New feature (non-breaking change which adds functionality)
  • Tweak (non-breaking change to improve existing functionality)

Checklist:

  • My code has been run through clang-format.
  • I have read the contributing document.
  • My code is not on the master branch.
  • The code has been tested.
  • All commit messages are properly formatted and commits squashed where appropriate.
  • I have included updates to all appropriate documentation.

@Warchamp7 Warchamp7 added the UI/UX Anything to do with changes or additions to UI/UX elements. label Apr 20, 2025
@Penwy
Copy link
Contributor

Penwy commented Apr 20, 2025

Testing on Ubuntu 24.04,
three suggestions :

  • when you add an existing one, have a confirmation button after selecting it, instead of adding it the moment you click.
  • a way to show again the "recently added" of all source types once you have selected a given source type (basically to "unselect" a source type).
  • bit unsure about this one but the "recently added" sources when no sources have been added manually during the session is based on the most recently added ones during scene collection load, no? If so maybe a way to not add to that list sources created during sc load? idk if that makes sense

one visual bug :

  • in all themes except classic, the right bit of the right column of source types gets cut off
    Selection_3687

@Warchamp7 Warchamp7 added the Seeking Testers Build artifacts on CI label Apr 20, 2025
@Penwy
Copy link
Contributor

Penwy commented Apr 21, 2025

Two additional notes after playing more with it :

  • the purple color when selecting a source type is unchanged by the theme, so it doesn't fit in some themes, typically in the light theme it makes select source type quite hard to read because of the black text.
    Selection_3706
  • the "make source visible" toggle is imo too far away and would benefit from being moved closer to the column where sources are created instead of hanging below the source types.
    Selection_3707

@Warchamp7 Warchamp7 force-pushed the add-source-window branch 2 times, most recently from 80e620b to 2501fb3 Compare April 24, 2025 18:31
@Warchamp7 Warchamp7 marked this pull request as draft May 14, 2025 01:09
@Warchamp7 Warchamp7 added this to the OBS Studio 32.0 milestone Jun 16, 2025
@Warchamp7 Warchamp7 force-pushed the add-source-window branch 6 times, most recently from 08da97b to 5bf01aa Compare July 17, 2025 21:10
@Warchamp7
Copy link
Member Author

PR has been updated with a new design and UI altogether

image

@Warchamp7 Warchamp7 force-pushed the add-source-window branch 3 times, most recently from 3e0730e to abddce3 Compare July 23, 2025 14:32
@Warchamp7 Warchamp7 force-pushed the add-source-window branch 2 times, most recently from 348d8f2 to b738ffd Compare September 3, 2025 18:32
@Warchamp7
Copy link
Member Author

This has been updated with a bunch of cleanup and optimizations by @Lain-B. It is ready for proper testing and review now

@Warchamp7 Warchamp7 requested a review from tytan652 September 3, 2025 18:40
@Warchamp7 Warchamp7 marked this pull request as ready for review September 3, 2025 18:47
Copy link
Member

@PatTheMav PatTheMav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First very superficial review, the Singleton pattern in the ThumbnailManager is an issue and appears at first glance like a responsibility inversion, will have to analyse this more deeply first.

There a few Qt-isms and C-isms that should use modern C++ style instead.

@Warchamp7 Warchamp7 force-pushed the add-source-window branch 2 times, most recently from fb6ec34 to b5e91c7 Compare September 6, 2025 21:21
@Warchamp7
Copy link
Member Author

Pushed some final cleanup as separate commits to make review of those changes easier.

As far as I am concerned, this PR is now ready for merge pending final code review.

Copy link
Member

@PatTheMav PatTheMav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed is that the text input box to create a new source does not have input focus automatically.

At least in my first attempts at using the new dialog, I didn't understand that this was indeed a text input field. Styling-wise it seemed like a label to me and it was only by clicking into it (and thus getting keyboard focus including a text input cursor) that I understood that I could type in it.

Some interfaces work around this discoverability problem by giving the input box a blinking text cursor, thereby suggesting "you can/should type something in here".

This probably only makes sense when no existing source of the same type is available, because you'd have no choice but to create the first one of that type. For accessibility reasons the text input probably should not have automatic focus if any existing source is available for selection, which only leaves with the input box being visually too generic to be identified as such.

Comment on lines +47 to +54
std::string typeId = type.toStdString();
const char *unversionedId = typeId.c_str();

if (strcmp(id, window->id) == 0)
window->ui->sourceList->addItem(QT_UTF8(name));

return true;
}

bool OBSBasicSourceSelect::EnumGroups(void *data, obs_source_t *source)
{
OBSBasicSourceSelect *window = static_cast<OBSBasicSourceSelect *>(data);
const char *name = obs_source_get_name(source);
const char *id = obs_source_get_unversioned_id(source);

if (strcmp(id, window->id) == 0) {
OBSBasic *main = OBSBasic::Get();
OBSScene scene = main->GetCurrentScene();

obs_sceneitem_t *existing = obs_scene_get_group(scene, name);
if (!existing)
window->ui->sourceList->addItem(QT_UTF8(name));
if (strcmp(unversionedId, "scene") == 0) {
return Str("Basic.Scene");
}

return true;
const char *id = obs_get_latest_input_type_id(unversionedId);
return obs_source_get_display_name(id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string typeId = type.toStdString();
const char *unversionedId = typeId.c_str();
if (strcmp(id, window->id) == 0)
window->ui->sourceList->addItem(QT_UTF8(name));
return true;
}
bool OBSBasicSourceSelect::EnumGroups(void *data, obs_source_t *source)
{
OBSBasicSourceSelect *window = static_cast<OBSBasicSourceSelect *>(data);
const char *name = obs_source_get_name(source);
const char *id = obs_source_get_unversioned_id(source);
if (strcmp(id, window->id) == 0) {
OBSBasic *main = OBSBasic::Get();
OBSScene scene = main->GetCurrentScene();
obs_sceneitem_t *existing = obs_scene_get_group(scene, name);
if (!existing)
window->ui->sourceList->addItem(QT_UTF8(name));
if (strcmp(unversionedId, "scene") == 0) {
return Str("Basic.Scene");
}
return true;
const char *id = obs_get_latest_input_type_id(unversionedId);
return obs_source_get_display_name(id);
if (type == "scene") {
return Str("Basic.Scene");
}
std::string unversionedId{type.toUtf8().constData()};
std::string_view inputTypeId = obs_get_latest_input_type_id(unversionedId.c_str());
std::string_view displayId = obs_source_get_display_name(inputTypeId.data());
if (displayId) {
return displayId.data();
} else {
return nullptr;
}

As this is a C++ implementation, I'd prefer if this also leans into C++ functionality:

  • QString can do comparisons against an (implicitly UTF-8 encoded) string constant, so we can use that directly (and don't need to reach down to lower level C via strcmp).
  • std::string (at least in C++17, with C++20 and more recent we should then use std::u8string) then takes ownership of the temporary UTF-8 string Qt will generate from its internal UTF-16 variant (if nothing "owns" the data returned by constData(), it will be deallocated once the temporary goes out of scope).
  • After that std::string_view is used as a C++ container for the data allocated by libobs (avoiding copies).
  • Finally the underlying const char * pointer created by obs_source_get_display_name is returned.

Note that this also requires handling the fail condition (either libobs library call returning nullptr) necessary and thus makes it explicit that the function itself can (and will) return a nullptr itself (so callers need to be able to handle that as well).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked the C++ docs a bit more and it might be that the function can even be changed to return std::string_view directly as it will automatically be converted into const char*, std::string, or std::string_view depending on the caller's needs.

It still obfuscates that the string is owned by libobs (and was created by obs_source_get_display_name) and needs to be manually freed at some point, but that's C libraries for ya.


if (!items.count())
return;
dstr_printf(&new_name, format, name, ++inc + 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually I'd prefer if this function would use C++ string types rather than lower-level C code, however C++17 does not have good built-in string formatting options and I'd like to think that using a printf-like variant here will be more readable than a bunch of std::string-style append operations.

#include <functional>
#include <deque>

class ThumbnailItem : public QObject {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ii ThumbnailItem a "public" object (i.e. used by other code then ThumbnailManager?

Same question about the Thumbnail class?

Comment on lines +70 to +71
static constexpr int cx = 320;
static constexpr int cy = 180;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why this doesn't use a size type like QSize or OBS::Rect that makes it clear that these are indeed not 2 independent values but have a combined meaning?

@PatTheMav
Copy link
Member

Another thing I noticed is that deprecated source types like "Window Capture" and "Desktop Capture" are presented as bona-fide source types and are neither displayed with lower priority in the left-hand list, nor do they retain a deprecation marker.

@Penwy
Copy link
Contributor

Penwy commented Nov 7, 2025

After testing latest (Ubuntu 24.04 in case) :

Two theming issues :

  • On Yami - Classic, when the source name text field is in focus, it has no border and is indistiguishable from the background.
Selection_4613
  • On Yami - Light, the Create New button is hardly legible when not hovered.
Selection_4614

Two suggestions :

  • Double clicking one of the existing sources should add an item of that source, in the same way that double clicking a source type does add a new source of that type.

  • I feel the Recently Added tab should be made to stand out more from the list, I would suggest by putting a separator between it and the rest of the list, and/or by giving it an icon to bring it level with the list. Rough mockup attached.

Selection_4611

@Warchamp7
Copy link
Member Author

Fixed the above visual issues

Two suggestions :

  • Double clicking one of the existing sources should add an item of that source, in the same way that double clicking a source type does add a new source of that type.

I toyed with this idea, but since the items are multi-selectable and can be unselected by clicking, double clicking was a bit confusing.

  • I feel the Recently Added tab should be made to stand out more from the list, I would suggest by putting a separator between it and the rest of the list, and/or by giving it an icon to bring it level with the list. Rough mockup attached.

I aimed to distinguish it with the lack of an icon. Adding a separator is also non-trivial due to how simplistic QListWidgets are heh

@Penwy
Copy link
Contributor

Penwy commented Nov 18, 2025

Fixed the above visual issues

Can confirm, also did a round of all themes to check for other visual issues, found none.

I aimed to distinguish it with the lack of an icon.

While I agree it is a visual distinction, it does, in my opinion, make it stand out less, as the eye is naturally drawn to the icons as "markers" of the list. Without the presence of such a marker, the "Recently added" does not impart that it is a list item at first sight.

Adding a separator is also non-trivial due to how simplistic QListWidgets are heh

Would it be possible to make it not be the same list but in a separate one(that's what I had in mind in the mockup), or not a list item at all, but still behave like one?

Copy link
Member

@RytoEX RytoEX left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure that new code complies with #12567.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Seeking Testers Build artifacts on CI UI/UX Anything to do with changes or additions to UI/UX elements.

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

6 participants