| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "calls/ui/calls_device_menu.h"
- #include "lang/lang_keys.h"
- #include "ui/widgets/menu/menu_item_base.h"
- #include "ui/widgets/checkbox.h"
- #include "ui/widgets/labels.h"
- #include "ui/widgets/popup_menu.h"
- #include "ui/widgets/scroll_area.h"
- #include "ui/wrap/vertical_layout.h"
- #include "webrtc/webrtc_device_common.h"
- #include "webrtc/webrtc_environment.h"
- #include "styles/style_calls.h"
- #include "styles/style_layers.h"
- namespace Calls {
- namespace {
- class Subsection final : public Ui::Menu::ItemBase {
- public:
- Subsection(
- not_null<RpWidget*> parent,
- const style::Menu &st,
- const QString &text);
- not_null<QAction*> action() const override;
- bool isEnabled() const override;
- private:
- int contentHeight() const override;
- const style::Menu &_st;
- const base::unique_qptr<Ui::FlatLabel> _text;
- const not_null<QAction*> _dummyAction;
- };
- class Selector final : public Ui::Menu::ItemBase {
- public:
- Selector(
- not_null<RpWidget*> parent,
- const style::Menu &st,
- rpl::producer<std::vector<Webrtc::DeviceInfo>> devices,
- rpl::producer<Webrtc::DeviceResolvedId> chosen,
- Fn<void(QString)> selected);
- not_null<QAction*> action() const override;
- bool isEnabled() const override;
- private:
- int contentHeight() const override;
- [[nodiscard]] int registerId(const QString &id);
- const base::unique_qptr<Ui::ScrollArea> _scroll;
- const not_null<Ui::VerticalLayout*> _list;
- const not_null<QAction*> _dummyAction;
- base::flat_map<QString, int> _ids;
- };
- Subsection::Subsection(
- not_null<RpWidget*> parent,
- const style::Menu &st,
- const QString &text)
- : Ui::Menu::ItemBase(parent, st)
- , _st(st)
- , _text(base::make_unique_q<Ui::FlatLabel>(
- this,
- text,
- st::callDeviceSelectionLabel))
- , _dummyAction(new QAction(parent)) {
- setPointerCursor(false);
- initResizeHook(parent->sizeValue());
- _text->resizeToWidth(st::callDeviceSelectionLabel.minWidth);
- _text->moveToLeft(st.itemPadding.left(), st.itemPadding.top());
- }
- not_null<QAction*> Subsection::action() const {
- return _dummyAction;
- }
- bool Subsection::isEnabled() const {
- return false;
- }
- int Subsection::contentHeight() const {
- return _st.itemPadding.top()
- + _text->height()
- + _st.itemPadding.bottom();
- }
- Selector::Selector(
- not_null<RpWidget*> parent,
- const style::Menu &st,
- rpl::producer<std::vector<Webrtc::DeviceInfo>> devices,
- rpl::producer<Webrtc::DeviceResolvedId> chosen,
- Fn<void(QString)> selected)
- : Ui::Menu::ItemBase(parent, st)
- , _scroll(base::make_unique_q<Ui::ScrollArea>(this))
- , _list(_scroll->setOwnedWidget(object_ptr<Ui::VerticalLayout>(this)))
- , _dummyAction(new QAction(parent)) {
- setPointerCursor(false);
- initResizeHook(parent->sizeValue());
- const auto padding = st.itemPadding;
- const auto group = std::make_shared<Ui::RadiobuttonGroup>();
- std::move(
- chosen
- ) | rpl::start_with_next([=](Webrtc::DeviceResolvedId id) {
- const auto value = id.isDefault() ? 0 : registerId(id.value);
- if (!group->hasValue() || group->current() != value) {
- group->setValue(value);
- }
- }, lifetime());
- group->setChangedCallback([=](int value) {
- if (value == 0) {
- selected({});
- } else {
- for (const auto &[id, index] : _ids) {
- if (index == value) {
- selected(id);
- break;
- }
- }
- }
- });
- std::move(
- devices
- ) | rpl::start_with_next([=](const std::vector<Webrtc::DeviceInfo> &v) {
- while (_list->count()) {
- delete _list->widgetAt(0);
- }
- _list->add(
- object_ptr<Ui::Radiobutton>(
- _list.get(),
- group,
- 0,
- tr::lng_settings_call_device_default(tr::now),
- st::groupCallCheckbox,
- st::groupCallRadio),
- padding);
- for (const auto &device : v) {
- if (device.inactive) {
- continue;
- }
- _list->add(
- object_ptr<Ui::Radiobutton>(
- _list.get(),
- group,
- registerId(device.id),
- device.name,
- st::groupCallCheckbox,
- st::groupCallRadio),
- padding);
- }
- resize(width(), contentHeight());
- }, lifetime());
- }
- not_null<QAction*> Selector::action() const {
- return _dummyAction;
- }
- bool Selector::isEnabled() const {
- return false;
- }
- int Selector::contentHeight() const {
- _list->resizeToWidth(width());
- if (_list->count() <= 3) {
- _scroll->resize(width(), _list->height());
- } else {
- _scroll->resize(
- width(),
- 3.5 * st::defaultRadio.diameter);
- }
- return _scroll->height();
- }
- int Selector::registerId(const QString &id) {
- auto &result = _ids[id];
- if (!result) {
- result = int(_ids.size());
- }
- return result;
- }
- void AddDeviceSelection(
- not_null<Ui::PopupMenu*> menu,
- not_null<Webrtc::Environment*> environment,
- DeviceSelection type,
- Fn<void(QString)> selected) {
- const auto title = [&] {
- switch (type.type) {
- case Webrtc::DeviceType::Camera:
- return tr::lng_settings_call_camera(tr::now);
- case Webrtc::DeviceType::Playback:
- return tr::lng_settings_call_section_output(tr::now);
- case Webrtc::DeviceType::Capture:
- return tr::lng_settings_call_section_input(tr::now);
- }
- Unexpected("Type in AddDeviceSelection.");
- }();
- menu->addAction(
- base::make_unique_q<Subsection>(menu, menu->st().menu, title));
- menu->addAction(
- base::make_unique_q<Selector>(
- menu,
- menu->st().menu,
- environment->devicesValue(type.type),
- std::move(type.chosen),
- selected));
- }
- } // namespace
- base::unique_qptr<Ui::PopupMenu> MakeDeviceSelectionMenu(
- not_null<Ui::RpWidget*> parent,
- not_null<Webrtc::Environment*> environment,
- std::vector<DeviceSelection> types,
- Fn<void(Webrtc::DeviceType, QString)> choose) {
- auto result = base::make_unique_q<Ui::PopupMenu>(
- parent,
- st::callDeviceSelectionMenu);
- const auto raw = result.get();
- for (auto type : types) {
- if (!raw->empty()) {
- raw->addSeparator();
- }
- const auto selected = [=, type = type.type](QString id) {
- choose(type, id);
- };
- AddDeviceSelection(raw, environment, std::move(type), selected);
- }
- return result;
- }
- } // namespace Calls
|