context-bar-controls.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. #include "context-bar-controls.hpp"
  2. #include "qt-wrappers.hpp"
  3. #include "obs-app.hpp"
  4. #include <QStandardItemModel>
  5. #include <QColorDialog>
  6. #include <QFontDialog>
  7. #include "ui_browser-source-toolbar.h"
  8. #include "ui_device-select-toolbar.h"
  9. #include "ui_game-capture-toolbar.h"
  10. #include "ui_image-source-toolbar.h"
  11. #include "ui_color-source-toolbar.h"
  12. #include "ui_text-source-toolbar.h"
  13. #ifdef _WIN32
  14. #define get_os_module(win, mac, linux) obs_get_module(win)
  15. #define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, win)
  16. #elif __APPLE__
  17. #define get_os_module(win, mac, linux) obs_get_module(mac)
  18. #define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, mac)
  19. #else
  20. #define get_os_module(win, mac, linux) obs_get_module(linux)
  21. #define get_os_text(mod, win, mac, linux) obs_module_get_locale_text(mod, linux)
  22. #endif
  23. /* ========================================================================= */
  24. SourceToolbar::SourceToolbar(QWidget *parent, OBSSource source)
  25. : QWidget(parent),
  26. weakSource(OBSGetWeakRef(source)),
  27. props(obs_source_properties(source), obs_properties_destroy)
  28. {
  29. }
  30. /* ========================================================================= */
  31. BrowserToolbar::BrowserToolbar(QWidget *parent, OBSSource source)
  32. : SourceToolbar(parent, source), ui(new Ui_BrowserSourceToolbar)
  33. {
  34. ui->setupUi(this);
  35. }
  36. BrowserToolbar::~BrowserToolbar()
  37. {
  38. delete ui;
  39. }
  40. void BrowserToolbar::on_refresh_clicked()
  41. {
  42. OBSSource source = GetSource();
  43. if (!source) {
  44. return;
  45. }
  46. obs_property_t *p = obs_properties_get(props.get(), "refreshnocache");
  47. obs_property_button_clicked(p, source.Get());
  48. }
  49. /* ========================================================================= */
  50. ComboSelectToolbar::ComboSelectToolbar(QWidget *parent, OBSSource source)
  51. : SourceToolbar(parent, source), ui(new Ui_DeviceSelectToolbar)
  52. {
  53. ui->setupUi(this);
  54. }
  55. ComboSelectToolbar::~ComboSelectToolbar()
  56. {
  57. delete ui;
  58. }
  59. static int FillPropertyCombo(QComboBox *c, obs_property_t *p,
  60. const std::string &cur_id, bool is_int = false)
  61. {
  62. size_t count = obs_property_list_item_count(p);
  63. int cur_idx = -1;
  64. for (size_t i = 0; i < count; i++) {
  65. const char *name = obs_property_list_item_name(p, i);
  66. std::string id;
  67. if (is_int) {
  68. id = std::to_string(obs_property_list_item_int(p, i));
  69. } else {
  70. const char *val = obs_property_list_item_string(p, i);
  71. id = val ? val : "";
  72. }
  73. if (cur_id == id)
  74. cur_idx = (int)i;
  75. c->addItem(name, id.c_str());
  76. }
  77. return cur_idx;
  78. }
  79. static void SetComboItemDisabled(QComboBox *c, int idx)
  80. {
  81. QStandardItemModel *model =
  82. dynamic_cast<QStandardItemModel *>(c->model());
  83. QStandardItem *item = model->item(idx);
  84. item->setFlags(Qt::NoItemFlags);
  85. }
  86. void UpdateSourceComboToolbarProperties(QComboBox *combo, OBSSource source,
  87. obs_properties_t *props,
  88. const char *prop_name, bool is_int)
  89. {
  90. std::string cur_id;
  91. obs_data_t *settings = obs_source_get_settings(source);
  92. if (is_int) {
  93. cur_id = std::to_string(obs_data_get_int(settings, prop_name));
  94. } else {
  95. cur_id = obs_data_get_string(settings, prop_name);
  96. }
  97. obs_data_release(settings);
  98. combo->blockSignals(true);
  99. obs_property_t *p = obs_properties_get(props, prop_name);
  100. int cur_idx = FillPropertyCombo(combo, p, cur_id, is_int);
  101. if (cur_idx == -1 || obs_property_list_item_disabled(p, cur_idx)) {
  102. if (cur_idx == -1) {
  103. combo->insertItem(
  104. 0,
  105. QTStr("Basic.Settings.Audio.UnknownAudioDevice"));
  106. cur_idx = 0;
  107. }
  108. SetComboItemDisabled(combo, cur_idx);
  109. }
  110. combo->setCurrentIndex(cur_idx);
  111. combo->blockSignals(false);
  112. }
  113. void ComboSelectToolbar::Init()
  114. {
  115. OBSSource source = GetSource();
  116. if (!source) {
  117. return;
  118. }
  119. UpdateSourceComboToolbarProperties(ui->device, source, props.get(),
  120. prop_name, is_int);
  121. }
  122. void UpdateSourceComboToolbarValue(QComboBox *combo, OBSSource source, int idx,
  123. const char *prop_name, bool is_int)
  124. {
  125. QString id = combo->itemData(idx).toString();
  126. obs_data_t *settings = obs_data_create();
  127. if (is_int) {
  128. obs_data_set_int(settings, prop_name, id.toInt());
  129. } else {
  130. obs_data_set_string(settings, prop_name, QT_TO_UTF8(id));
  131. }
  132. obs_source_update(source, settings);
  133. obs_data_release(settings);
  134. }
  135. void ComboSelectToolbar::on_device_currentIndexChanged(int idx)
  136. {
  137. OBSSource source = GetSource();
  138. if (idx == -1 || !source) {
  139. return;
  140. }
  141. UpdateSourceComboToolbarValue(ui->device, source, idx, prop_name,
  142. is_int);
  143. }
  144. AudioCaptureToolbar::AudioCaptureToolbar(QWidget *parent, OBSSource source)
  145. : ComboSelectToolbar(parent, source)
  146. {
  147. }
  148. void AudioCaptureToolbar::Init()
  149. {
  150. delete ui->activateButton;
  151. ui->activateButton = nullptr;
  152. obs_module_t *mod =
  153. get_os_module("win-wasapi", "mac-capture", "linux-pulseaudio");
  154. const char *device_str =
  155. get_os_text(mod, "Device", "CoreAudio.Device", "Device");
  156. ui->deviceLabel->setText(device_str);
  157. prop_name = "device_id";
  158. ComboSelectToolbar::Init();
  159. }
  160. WindowCaptureToolbar::WindowCaptureToolbar(QWidget *parent, OBSSource source)
  161. : ComboSelectToolbar(parent, source)
  162. {
  163. }
  164. void WindowCaptureToolbar::Init()
  165. {
  166. delete ui->activateButton;
  167. ui->activateButton = nullptr;
  168. obs_module_t *mod =
  169. get_os_module("win-capture", "mac-capture", "linux-capture");
  170. const char *device_str = get_os_text(mod, "WindowCapture.Window",
  171. "WindowUtils.Window", "Window");
  172. ui->deviceLabel->setText(device_str);
  173. #if !defined(_WIN32) && !defined(__APPLE__) //linux
  174. prop_name = "capture_window";
  175. #else
  176. prop_name = "window";
  177. #endif
  178. #ifdef __APPLE__
  179. is_int = true;
  180. #endif
  181. ComboSelectToolbar::Init();
  182. }
  183. DisplayCaptureToolbar::DisplayCaptureToolbar(QWidget *parent, OBSSource source)
  184. : ComboSelectToolbar(parent, source)
  185. {
  186. }
  187. void DisplayCaptureToolbar::Init()
  188. {
  189. delete ui->activateButton;
  190. ui->activateButton = nullptr;
  191. obs_module_t *mod =
  192. get_os_module("win-capture", "mac-capture", "linux-capture");
  193. const char *device_str =
  194. get_os_text(mod, "Monitor", "DisplayCapture.Display", "Screen");
  195. ui->deviceLabel->setText(device_str);
  196. is_int = true;
  197. #ifdef _WIN32
  198. prop_name = "monitor";
  199. #elif __APPLE__
  200. prop_name = "display";
  201. #else
  202. prop_name = "screen";
  203. #endif
  204. ComboSelectToolbar::Init();
  205. }
  206. /* ========================================================================= */
  207. DeviceCaptureToolbar::DeviceCaptureToolbar(QWidget *parent, OBSSource source)
  208. : QWidget(parent),
  209. weakSource(OBSGetWeakRef(source)),
  210. ui(new Ui_DeviceSelectToolbar)
  211. {
  212. ui->setupUi(this);
  213. delete ui->deviceLabel;
  214. delete ui->device;
  215. ui->deviceLabel = nullptr;
  216. ui->device = nullptr;
  217. obs_data_t *settings = obs_source_get_settings(source);
  218. active = obs_data_get_bool(settings, "active");
  219. obs_data_release(settings);
  220. obs_module_t *mod = obs_get_module("win-dshow");
  221. activateText = obs_module_get_locale_text(mod, "Activate");
  222. deactivateText = obs_module_get_locale_text(mod, "Deactivate");
  223. ui->activateButton->setText(active ? deactivateText : activateText);
  224. }
  225. DeviceCaptureToolbar::~DeviceCaptureToolbar()
  226. {
  227. delete ui;
  228. }
  229. void DeviceCaptureToolbar::on_activateButton_clicked()
  230. {
  231. OBSSource source = OBSGetStrongRef(weakSource);
  232. if (!source) {
  233. return;
  234. }
  235. obs_data_t *settings = obs_source_get_settings(source);
  236. bool now_active = obs_data_get_bool(settings, "active");
  237. obs_data_release(settings);
  238. bool desyncedSetting = now_active != active;
  239. active = !active;
  240. const char *text = active ? deactivateText : activateText;
  241. ui->activateButton->setText(text);
  242. if (desyncedSetting) {
  243. return;
  244. }
  245. calldata_t cd = {};
  246. calldata_set_bool(&cd, "active", active);
  247. proc_handler_t *ph = obs_source_get_proc_handler(source);
  248. proc_handler_call(ph, "activate", &cd);
  249. calldata_free(&cd);
  250. }
  251. /* ========================================================================= */
  252. GameCaptureToolbar::GameCaptureToolbar(QWidget *parent, OBSSource source)
  253. : SourceToolbar(parent, source), ui(new Ui_GameCaptureToolbar)
  254. {
  255. obs_property_t *p;
  256. int cur_idx;
  257. ui->setupUi(this);
  258. obs_module_t *mod = obs_get_module("win-capture");
  259. ui->modeLabel->setText(obs_module_get_locale_text(mod, "Mode"));
  260. ui->windowLabel->setText(
  261. obs_module_get_locale_text(mod, "WindowCapture.Window"));
  262. obs_data_t *settings = obs_source_get_settings(source);
  263. std::string cur_mode = obs_data_get_string(settings, "capture_mode");
  264. std::string cur_window = obs_data_get_string(settings, "window");
  265. obs_data_release(settings);
  266. ui->mode->blockSignals(true);
  267. p = obs_properties_get(props.get(), "capture_mode");
  268. cur_idx = FillPropertyCombo(ui->mode, p, cur_mode);
  269. ui->mode->setCurrentIndex(cur_idx);
  270. ui->mode->blockSignals(false);
  271. ui->window->blockSignals(true);
  272. p = obs_properties_get(props.get(), "window");
  273. cur_idx = FillPropertyCombo(ui->window, p, cur_window);
  274. ui->window->setCurrentIndex(cur_idx);
  275. ui->window->blockSignals(false);
  276. if (cur_idx != -1 && obs_property_list_item_disabled(p, cur_idx)) {
  277. SetComboItemDisabled(ui->window, cur_idx);
  278. }
  279. UpdateWindowVisibility();
  280. }
  281. GameCaptureToolbar::~GameCaptureToolbar()
  282. {
  283. delete ui;
  284. }
  285. void GameCaptureToolbar::UpdateWindowVisibility()
  286. {
  287. QString mode = ui->mode->currentData().toString();
  288. bool is_window = (mode == "window");
  289. ui->windowLabel->setVisible(is_window);
  290. ui->window->setVisible(is_window);
  291. ui->empty->setVisible(!is_window);
  292. }
  293. void GameCaptureToolbar::on_mode_currentIndexChanged(int idx)
  294. {
  295. OBSSource source = GetSource();
  296. if (idx == -1 || !source) {
  297. return;
  298. }
  299. QString id = ui->mode->itemData(idx).toString();
  300. obs_data_t *settings = obs_data_create();
  301. obs_data_set_string(settings, "capture_mode", QT_TO_UTF8(id));
  302. obs_source_update(source, settings);
  303. obs_data_release(settings);
  304. UpdateWindowVisibility();
  305. }
  306. void GameCaptureToolbar::on_window_currentIndexChanged(int idx)
  307. {
  308. OBSSource source = GetSource();
  309. if (idx == -1 || !source) {
  310. return;
  311. }
  312. QString id = ui->window->itemData(idx).toString();
  313. obs_data_t *settings = obs_data_create();
  314. obs_data_set_string(settings, "window", QT_TO_UTF8(id));
  315. obs_source_update(source, settings);
  316. obs_data_release(settings);
  317. }
  318. /* ========================================================================= */
  319. ImageSourceToolbar::ImageSourceToolbar(QWidget *parent, OBSSource source)
  320. : SourceToolbar(parent, source), ui(new Ui_ImageSourceToolbar)
  321. {
  322. ui->setupUi(this);
  323. obs_module_t *mod = obs_get_module("image-source");
  324. ui->pathLabel->setText(obs_module_get_locale_text(mod, "File"));
  325. obs_data_t *settings = obs_source_get_settings(source);
  326. std::string file = obs_data_get_string(settings, "file");
  327. obs_data_release(settings);
  328. ui->path->setText(file.c_str());
  329. }
  330. ImageSourceToolbar::~ImageSourceToolbar()
  331. {
  332. delete ui;
  333. }
  334. void ImageSourceToolbar::on_browse_clicked()
  335. {
  336. OBSSource source = GetSource();
  337. if (!source) {
  338. return;
  339. }
  340. obs_property_t *p = obs_properties_get(props.get(), "file");
  341. const char *desc = obs_property_description(p);
  342. const char *filter = obs_property_path_filter(p);
  343. const char *default_path = obs_property_path_default_path(p);
  344. QString path = OpenFile(this, desc, default_path, filter);
  345. if (path.isEmpty()) {
  346. return;
  347. }
  348. ui->path->setText(path);
  349. obs_data_t *settings = obs_data_create();
  350. obs_data_set_string(settings, "file", QT_TO_UTF8(path));
  351. obs_source_update(source, settings);
  352. obs_data_release(settings);
  353. }
  354. /* ========================================================================= */
  355. static inline QColor color_from_int(long long val)
  356. {
  357. return QColor(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff,
  358. (val >> 24) & 0xff);
  359. }
  360. static inline long long color_to_int(QColor color)
  361. {
  362. auto shift = [&](unsigned val, int shift) {
  363. return ((val & 0xff) << shift);
  364. };
  365. return shift(color.red(), 0) | shift(color.green(), 8) |
  366. shift(color.blue(), 16) | shift(color.alpha(), 24);
  367. }
  368. ColorSourceToolbar::ColorSourceToolbar(QWidget *parent, OBSSource source)
  369. : SourceToolbar(parent, source), ui(new Ui_ColorSourceToolbar)
  370. {
  371. ui->setupUi(this);
  372. obs_data_t *settings = obs_source_get_settings(source);
  373. unsigned int val = (unsigned int)obs_data_get_int(settings, "color");
  374. obs_data_release(settings);
  375. color = color_from_int(val);
  376. UpdateColor();
  377. }
  378. ColorSourceToolbar::~ColorSourceToolbar()
  379. {
  380. delete ui;
  381. }
  382. void ColorSourceToolbar::UpdateColor()
  383. {
  384. color.setAlpha(255);
  385. QPalette palette = QPalette(color);
  386. ui->color->setFrameStyle(QFrame::Sunken | QFrame::Panel);
  387. ui->color->setText(color.name(QColor::HexRgb));
  388. ui->color->setPalette(palette);
  389. ui->color->setStyleSheet(
  390. QString("background-color :%1; color: %2;")
  391. .arg(palette.color(QPalette::Window)
  392. .name(QColor::HexRgb))
  393. .arg(palette.color(QPalette::WindowText)
  394. .name(QColor::HexRgb)));
  395. ui->color->setAutoFillBackground(true);
  396. ui->color->setAlignment(Qt::AlignCenter);
  397. }
  398. void ColorSourceToolbar::on_choose_clicked()
  399. {
  400. OBSSource source = GetSource();
  401. if (!source) {
  402. return;
  403. }
  404. obs_property_t *p = obs_properties_get(props.get(), "color");
  405. const char *desc = obs_property_description(p);
  406. QColorDialog::ColorDialogOptions options;
  407. #ifndef _WIN32
  408. options |= QColorDialog::DontUseNativeDialog;
  409. #endif
  410. QColor newColor = QColorDialog::getColor(color, this, desc, options);
  411. if (!newColor.isValid()) {
  412. return;
  413. }
  414. color = newColor;
  415. UpdateColor();
  416. obs_data_t *settings = obs_data_create();
  417. obs_data_set_int(settings, "color", color_to_int(color));
  418. obs_source_update(source, settings);
  419. obs_data_release(settings);
  420. }
  421. /* ========================================================================= */
  422. extern void MakeQFont(obs_data_t *font_obj, QFont &font, bool limit = false);
  423. TextSourceToolbar::TextSourceToolbar(QWidget *parent, OBSSource source)
  424. : SourceToolbar(parent, source), ui(new Ui_TextSourceToolbar)
  425. {
  426. ui->setupUi(this);
  427. obs_data_t *settings = obs_source_get_settings(source);
  428. const char *id = obs_source_get_unversioned_id(source);
  429. bool ft2 = strcmp(id, "text_ft2_source") == 0;
  430. bool read_from_file = obs_data_get_bool(
  431. settings, ft2 ? "from_file" : "read_from_file");
  432. obs_data_t *font_obj = obs_data_get_obj(settings, "font");
  433. MakeQFont(font_obj, font);
  434. obs_data_release(font_obj);
  435. unsigned int val = (unsigned int)obs_data_get_int(settings, "color");
  436. color = color_from_int(val);
  437. const char *text = obs_data_get_string(settings, "text");
  438. bool single_line = !read_from_file &&
  439. (!text || (strchr(text, '\n') == nullptr));
  440. ui->emptySpace->setVisible(!single_line);
  441. ui->text->setVisible(single_line);
  442. if (single_line)
  443. ui->text->setText(text);
  444. obs_data_release(settings);
  445. }
  446. TextSourceToolbar::~TextSourceToolbar()
  447. {
  448. delete ui;
  449. }
  450. void TextSourceToolbar::on_selectFont_clicked()
  451. {
  452. OBSSource source = GetSource();
  453. if (!source) {
  454. return;
  455. }
  456. QFontDialog::FontDialogOptions options;
  457. uint32_t flags;
  458. bool success;
  459. #ifndef _WIN32
  460. options = QFontDialog::DontUseNativeDialog;
  461. #endif
  462. font = QFontDialog::getFont(&success, font, this, "Pick a Font",
  463. options);
  464. if (!success) {
  465. return;
  466. }
  467. obs_data_t *font_obj = obs_data_create();
  468. obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family()));
  469. obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName()));
  470. obs_data_set_int(font_obj, "size", font.pointSize());
  471. flags = font.bold() ? OBS_FONT_BOLD : 0;
  472. flags |= font.italic() ? OBS_FONT_ITALIC : 0;
  473. flags |= font.underline() ? OBS_FONT_UNDERLINE : 0;
  474. flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0;
  475. obs_data_set_int(font_obj, "flags", flags);
  476. obs_data_t *settings = obs_data_create();
  477. obs_data_set_obj(settings, "font", font_obj);
  478. obs_data_release(font_obj);
  479. obs_source_update(source, settings);
  480. obs_data_release(settings);
  481. }
  482. void TextSourceToolbar::on_selectColor_clicked()
  483. {
  484. OBSSource source = GetSource();
  485. if (!source) {
  486. return;
  487. }
  488. obs_property_t *p = obs_properties_get(props.get(), "color");
  489. const char *desc = obs_property_description(p);
  490. QColorDialog::ColorDialogOptions options;
  491. #ifndef _WIN32
  492. options |= QColorDialog::DontUseNativeDialog;
  493. #endif
  494. QColor newColor = QColorDialog::getColor(color, this, desc, options);
  495. if (!newColor.isValid()) {
  496. return;
  497. }
  498. color = newColor;
  499. obs_data_t *settings = obs_data_create();
  500. if (!strncmp(obs_source_get_id(source), "text_ft2_source", 15)) {
  501. obs_data_set_int(settings, "color1", color_to_int(color));
  502. obs_data_set_int(settings, "color2", color_to_int(color));
  503. } else {
  504. obs_data_set_int(settings, "color", color_to_int(color));
  505. }
  506. obs_source_update(source, settings);
  507. obs_data_release(settings);
  508. }
  509. void TextSourceToolbar::on_text_textChanged()
  510. {
  511. OBSSource source = GetSource();
  512. if (!source) {
  513. return;
  514. }
  515. obs_data_t *settings = obs_data_create();
  516. obs_data_set_string(settings, "text", QT_TO_UTF8(ui->text->text()));
  517. obs_source_update(source, settings);
  518. obs_data_release(settings);
  519. }