properties-view.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #include <QFormLayout>
  2. #include <QScrollBar>
  3. #include <QLabel>
  4. #include <QCheckBox>
  5. #include <QFont>
  6. #include <QFontDialog>
  7. #include <QLineEdit>
  8. #include <QSpinBox>
  9. #include <QDoubleSpinBox>
  10. #include <QComboBox>
  11. #include <QPushButton>
  12. #include <QStandardItem>
  13. #include <QFileDialog>
  14. #include <QColorDialog>
  15. #include <QPlainTextEdit>
  16. #include "qt-wrappers.hpp"
  17. #include "properties-view.hpp"
  18. #include "obs-app.hpp"
  19. #include <string>
  20. using namespace std;
  21. static inline QColor color_from_int(long long val)
  22. {
  23. return QColor( val & 0xff,
  24. (val >> 8) & 0xff,
  25. (val >> 16) & 0xff,
  26. (val >> 24) & 0xff);
  27. }
  28. static inline long long color_to_int(QColor color)
  29. {
  30. auto shift = [&](unsigned val, int shift)
  31. {
  32. return ((val & 0xff) << shift);
  33. };
  34. return shift(color.red(), 0) |
  35. shift(color.green(), 8) |
  36. shift(color.blue(), 16) |
  37. shift(color.alpha(), 24);
  38. }
  39. void OBSPropertiesView::ReloadProperties()
  40. {
  41. if (obj) {
  42. properties.reset(reloadCallback(obj));
  43. } else {
  44. properties.reset(reloadCallback((void*)type.c_str()));
  45. obs_properties_apply_settings(properties.get(), settings);
  46. }
  47. RefreshProperties();
  48. }
  49. void OBSPropertiesView::RefreshProperties()
  50. {
  51. int h, v;
  52. GetScrollPos(h, v);
  53. children.clear();
  54. if (widget)
  55. widget->deleteLater();
  56. widget = new QWidget();
  57. QFormLayout *layout = new QFormLayout;
  58. layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
  59. widget->setLayout(layout);
  60. QSizePolicy mainPolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  61. QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred);
  62. //widget->setSizePolicy(policy);
  63. layout->setLabelAlignment(Qt::AlignRight);
  64. obs_property_t *property = obs_properties_first(properties.get());
  65. while (property) {
  66. AddProperty(property, layout);
  67. obs_property_next(&property);
  68. }
  69. setWidgetResizable(true);
  70. setWidget(widget);
  71. SetScrollPos(h, v);
  72. setSizePolicy(mainPolicy);
  73. lastFocused.clear();
  74. if (lastWidget) {
  75. lastWidget->setFocus(Qt::OtherFocusReason);
  76. lastWidget = nullptr;
  77. }
  78. }
  79. void OBSPropertiesView::SetScrollPos(int h, int v)
  80. {
  81. QScrollBar *scroll = horizontalScrollBar();
  82. if (scroll)
  83. scroll->setValue(h);
  84. scroll = verticalScrollBar();
  85. if (scroll)
  86. scroll->setValue(v);
  87. }
  88. void OBSPropertiesView::GetScrollPos(int &h, int &v)
  89. {
  90. h = v = 0;
  91. QScrollBar *scroll = horizontalScrollBar();
  92. if (scroll)
  93. h = scroll->value();
  94. scroll = verticalScrollBar();
  95. if (scroll)
  96. v = scroll->value();
  97. }
  98. OBSPropertiesView::OBSPropertiesView(OBSData settings_, void *obj_,
  99. PropertiesReloadCallback reloadCallback,
  100. PropertiesUpdateCallback callback_, int minSize_)
  101. : VScrollArea (nullptr),
  102. properties (nullptr, obs_properties_destroy),
  103. settings (settings_),
  104. obj (obj_),
  105. reloadCallback (reloadCallback),
  106. callback (callback_),
  107. minSize (minSize_)
  108. {
  109. setFrameShape(QFrame::NoFrame);
  110. ReloadProperties();
  111. }
  112. OBSPropertiesView::OBSPropertiesView(OBSData settings_, const char *type_,
  113. PropertiesReloadCallback reloadCallback_, int minSize_)
  114. : VScrollArea (nullptr),
  115. properties (nullptr, obs_properties_destroy),
  116. settings (settings_),
  117. type (type_),
  118. reloadCallback (reloadCallback_),
  119. minSize (minSize_)
  120. {
  121. setFrameShape(QFrame::NoFrame);
  122. ReloadProperties();
  123. }
  124. void OBSPropertiesView::resizeEvent(QResizeEvent *event)
  125. {
  126. emit PropertiesResized();
  127. VScrollArea::resizeEvent(event);
  128. }
  129. QWidget *OBSPropertiesView::NewWidget(obs_property_t *prop, QWidget *widget,
  130. const char *signal)
  131. {
  132. WidgetInfo *info = new WidgetInfo(this, prop, widget);
  133. connect(widget, signal, info, SLOT(ControlChanged()));
  134. children.push_back(std::move(unique_ptr<WidgetInfo>(info)));
  135. return widget;
  136. }
  137. QWidget *OBSPropertiesView::AddCheckbox(obs_property_t *prop)
  138. {
  139. const char *name = obs_property_name(prop);
  140. const char *desc = obs_property_description(prop);
  141. bool val = obs_data_get_bool(settings, name);
  142. QCheckBox *checkbox = new QCheckBox(QT_UTF8(desc));
  143. checkbox->setCheckState(val ? Qt::Checked : Qt::Unchecked);
  144. return NewWidget(prop, checkbox, SIGNAL(stateChanged(int)));
  145. }
  146. QWidget *OBSPropertiesView::AddText(obs_property_t *prop)
  147. {
  148. const char *name = obs_property_name(prop);
  149. const char *val = obs_data_get_string(settings, name);
  150. obs_text_type type = obs_proprety_text_type(prop);
  151. if (type == OBS_TEXT_MULTILINE) {
  152. QPlainTextEdit *edit = new QPlainTextEdit(QT_UTF8(val));
  153. return NewWidget(prop, edit, SIGNAL(textChanged()));
  154. }
  155. QLineEdit *edit = new QLineEdit();
  156. if (type == OBS_TEXT_PASSWORD)
  157. edit->setEchoMode(QLineEdit::Password);
  158. edit->setText(QT_UTF8(val));
  159. return NewWidget(prop, edit, SIGNAL(textEdited(const QString &)));
  160. }
  161. void OBSPropertiesView::AddPath(obs_property_t *prop, QFormLayout *layout,
  162. QLabel **label)
  163. {
  164. const char *name = obs_property_name(prop);
  165. const char *val = obs_data_get_string(settings, name);
  166. QLayout *subLayout = new QHBoxLayout();
  167. QLineEdit *edit = new QLineEdit();
  168. QPushButton *button = new QPushButton(QTStr("Browse"));
  169. edit->setText(QT_UTF8(val));
  170. edit->setReadOnly(true);
  171. subLayout->addWidget(edit);
  172. subLayout->addWidget(button);
  173. WidgetInfo *info = new WidgetInfo(this, prop, edit);
  174. connect(button, SIGNAL(clicked()), info, SLOT(ControlChanged()));
  175. children.push_back(std::move(unique_ptr<WidgetInfo>(info)));
  176. *label = new QLabel(QT_UTF8(obs_property_description(prop)));
  177. layout->addRow(*label, subLayout);
  178. }
  179. QWidget *OBSPropertiesView::AddInt(obs_property_t *prop)
  180. {
  181. const char *name = obs_property_name(prop);
  182. int val = (int)obs_data_get_int(settings, name);
  183. QSpinBox *spin = new QSpinBox();
  184. spin->setMinimum(obs_property_int_min(prop));
  185. spin->setMaximum(obs_property_int_max(prop));
  186. spin->setSingleStep(obs_property_int_step(prop));
  187. spin->setValue(val);
  188. return NewWidget(prop, spin, SIGNAL(valueChanged(int)));
  189. }
  190. QWidget *OBSPropertiesView::AddFloat(obs_property_t *prop)
  191. {
  192. const char *name = obs_property_name(prop);
  193. double val = obs_data_get_double(settings, name);
  194. QDoubleSpinBox *spin = new QDoubleSpinBox();
  195. spin->setMinimum(obs_property_float_min(prop));
  196. spin->setMaximum(obs_property_float_max(prop));
  197. spin->setSingleStep(obs_property_float_step(prop));
  198. spin->setValue(val);
  199. return NewWidget(prop, spin, SIGNAL(valueChanged(double)));
  200. }
  201. static void AddComboItem(QComboBox *combo, obs_property_t *prop,
  202. obs_combo_format format, size_t idx)
  203. {
  204. const char *name = obs_property_list_item_name(prop, idx);
  205. QVariant var;
  206. if (format == OBS_COMBO_FORMAT_INT) {
  207. long long val = obs_property_list_item_int(prop, idx);
  208. var = QVariant::fromValue<long long>(val);
  209. } else if (format == OBS_COMBO_FORMAT_FLOAT) {
  210. double val = obs_property_list_item_float(prop, idx);
  211. var = QVariant::fromValue<double>(val);
  212. } else if (format == OBS_COMBO_FORMAT_STRING) {
  213. var = obs_property_list_item_string(prop, idx);
  214. }
  215. combo->addItem(QT_UTF8(name), var);
  216. if (!obs_property_list_item_disabled(prop, idx))
  217. return;
  218. int index = combo->findText(QT_UTF8(name));
  219. if (index < 0)
  220. return;
  221. QStandardItemModel *model =
  222. dynamic_cast<QStandardItemModel*>(combo->model());
  223. if (!model)
  224. return;
  225. QStandardItem *item = model->item(index);
  226. item->setFlags(Qt::NoItemFlags);
  227. }
  228. template <long long get_int(obs_data_t*, const char*),
  229. double get_double(obs_data_t*, const char*),
  230. const char *get_string(obs_data_t*, const char*)>
  231. static string from_obs_data(obs_data_t *data, const char *name,
  232. obs_combo_format format)
  233. {
  234. switch (format) {
  235. case OBS_COMBO_FORMAT_INT:
  236. return to_string(get_int(data, name));
  237. case OBS_COMBO_FORMAT_FLOAT:
  238. return to_string(get_double(data, name));
  239. case OBS_COMBO_FORMAT_STRING:
  240. return get_string(data, name);
  241. default:
  242. return "";
  243. }
  244. }
  245. static string from_obs_data(obs_data_t *data, const char *name,
  246. obs_combo_format format)
  247. {
  248. return from_obs_data<obs_data_get_int, obs_data_get_double,
  249. obs_data_get_string>(data, name, format);
  250. }
  251. static string from_obs_data_autoselect(obs_data_t *data, const char *name,
  252. obs_combo_format format)
  253. {
  254. return from_obs_data<obs_data_get_autoselect_int,
  255. obs_data_get_autoselect_double,
  256. obs_data_get_autoselect_string>(data, name, format);
  257. }
  258. QWidget *OBSPropertiesView::AddList(obs_property_t *prop, bool &warning)
  259. {
  260. const char *name = obs_property_name(prop);
  261. QComboBox *combo = new QComboBox();
  262. obs_combo_type type = obs_property_list_type(prop);
  263. obs_combo_format format = obs_property_list_format(prop);
  264. size_t count = obs_property_list_item_count(prop);
  265. int idx = -1;
  266. for (size_t i = 0; i < count; i++)
  267. AddComboItem(combo, prop, format, i);
  268. if (type == OBS_COMBO_TYPE_EDITABLE)
  269. combo->setEditable(true);
  270. string value = from_obs_data(settings, name, format);
  271. if (format == OBS_COMBO_FORMAT_STRING &&
  272. type == OBS_COMBO_TYPE_EDITABLE)
  273. combo->lineEdit()->setText(QT_UTF8(value.c_str()));
  274. else
  275. idx = combo->findData(QT_UTF8(value.c_str()));
  276. if (type == OBS_COMBO_TYPE_EDITABLE)
  277. return NewWidget(prop, combo,
  278. SIGNAL(editTextChanged(const QString &)));
  279. if (idx != -1)
  280. combo->setCurrentIndex(idx);
  281. if (obs_data_has_autoselect_value(settings, name)) {
  282. string autoselect =
  283. from_obs_data_autoselect(settings, name, format);
  284. int id = combo->findData(QT_UTF8(autoselect.c_str()));
  285. if (id != -1 && id != idx) {
  286. QString actual = combo->itemText(id);
  287. QString selected = combo->itemText(idx);
  288. QString combined = QTStr(
  289. "Basic.PropertiesWindow.AutoSelectFormat");
  290. combo->setItemText(idx,
  291. combined.arg(selected).arg(actual));
  292. }
  293. }
  294. QAbstractItemModel *model = combo->model();
  295. warning = idx != -1 &&
  296. model->flags(model->index(idx, 0)) == Qt::NoItemFlags;
  297. WidgetInfo *info = new WidgetInfo(this, prop, combo);
  298. connect(combo, SIGNAL(currentIndexChanged(int)), info,
  299. SLOT(ControlChanged()));
  300. children.push_back(std::move(unique_ptr<WidgetInfo>(info)));
  301. /* trigger a settings update if the index was not found */
  302. if (idx == -1)
  303. info->ControlChanged();
  304. return combo;
  305. }
  306. QWidget *OBSPropertiesView::AddButton(obs_property_t *prop)
  307. {
  308. const char *desc = obs_property_description(prop);
  309. QPushButton *button = new QPushButton(QT_UTF8(desc));
  310. button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
  311. return NewWidget(prop, button, SIGNAL(clicked()));
  312. }
  313. void OBSPropertiesView::AddColor(obs_property_t *prop, QFormLayout *layout,
  314. QLabel *&label)
  315. {
  316. QPushButton *button = new QPushButton;
  317. QLabel *colorLabel = new QLabel;
  318. const char *name = obs_property_name(prop);
  319. long long val = obs_data_get_int(settings, name);
  320. QColor color = color_from_int(val);
  321. button->setText(QTStr("Basic.PropertiesWindow.SelectColor"));
  322. colorLabel->setFrameStyle(QFrame::Sunken | QFrame::Panel);
  323. colorLabel->setText(color.name(QColor::HexArgb));
  324. colorLabel->setPalette(QPalette(color));
  325. colorLabel->setAutoFillBackground(true);
  326. colorLabel->setAlignment(Qt::AlignCenter);
  327. QHBoxLayout *subLayout = new QHBoxLayout;
  328. subLayout->setContentsMargins(0, 0, 0, 0);
  329. subLayout->addWidget(colorLabel);
  330. subLayout->addWidget(button);
  331. WidgetInfo *info = new WidgetInfo(this, prop, colorLabel);
  332. connect(button, SIGNAL(clicked()), info, SLOT(ControlChanged()));
  333. children.emplace_back(info);
  334. label = new QLabel(QT_UTF8(obs_property_description(prop)));
  335. layout->addRow(label, subLayout);
  336. }
  337. static void MakeQFont(obs_data_t *font_obj, QFont &font)
  338. {
  339. const char *face = obs_data_get_string(font_obj, "face");
  340. const char *style = obs_data_get_string(font_obj, "style");
  341. int size = (int)obs_data_get_int(font_obj, "size");
  342. uint32_t flags = (uint32_t)obs_data_get_int(font_obj, "flags");
  343. if (face) {
  344. font.setFamily(face);
  345. font.setStyleName(style);
  346. }
  347. if (size)
  348. font.setPointSize(size);
  349. if (flags & OBS_FONT_BOLD) font.setBold(true);
  350. if (flags & OBS_FONT_ITALIC) font.setItalic(true);
  351. if (flags & OBS_FONT_UNDERLINE) font.setUnderline(true);
  352. if (flags & OBS_FONT_STRIKEOUT) font.setStrikeOut(true);
  353. }
  354. void OBSPropertiesView::AddFont(obs_property_t *prop, QFormLayout *layout,
  355. QLabel *&label)
  356. {
  357. const char *name = obs_property_name(prop);
  358. obs_data_t *font_obj = obs_data_get_obj(settings, name);
  359. const char *face = obs_data_get_string(font_obj, "face");
  360. const char *style = obs_data_get_string(font_obj, "style");
  361. QPushButton *button = new QPushButton;
  362. QLabel *fontLabel = new QLabel;
  363. QFont font;
  364. font = fontLabel->font();
  365. MakeQFont(font_obj, font);
  366. button->setText(QTStr("Basic.PropertiesWindow.SelectFont"));
  367. fontLabel->setFrameStyle(QFrame::Sunken | QFrame::Panel);
  368. fontLabel->setFont(font);
  369. fontLabel->setText(QString("%1 %2").arg(face, style));
  370. fontLabel->setAlignment(Qt::AlignCenter);
  371. QHBoxLayout *subLayout = new QHBoxLayout;
  372. subLayout->setContentsMargins(0, 0, 0, 0);
  373. subLayout->addWidget(fontLabel);
  374. subLayout->addWidget(button);
  375. WidgetInfo *info = new WidgetInfo(this, prop, fontLabel);
  376. connect(button, SIGNAL(clicked()), info, SLOT(ControlChanged()));
  377. children.emplace_back(info);
  378. label = new QLabel(QT_UTF8(obs_property_description(prop)));
  379. layout->addRow(label, subLayout);
  380. obs_data_release(font_obj);
  381. }
  382. void OBSPropertiesView::AddProperty(obs_property_t *property,
  383. QFormLayout *layout)
  384. {
  385. const char *name = obs_property_name(property);
  386. obs_property_type type = obs_property_get_type(property);
  387. if (!obs_property_visible(property))
  388. return;
  389. QLabel *label = nullptr;
  390. QWidget *widget = nullptr;
  391. bool warning = false;
  392. switch (type) {
  393. case OBS_PROPERTY_INVALID:
  394. return;
  395. case OBS_PROPERTY_BOOL:
  396. widget = AddCheckbox(property);
  397. break;
  398. case OBS_PROPERTY_INT:
  399. widget = AddInt(property);
  400. break;
  401. case OBS_PROPERTY_FLOAT:
  402. widget = AddFloat(property);
  403. break;
  404. case OBS_PROPERTY_TEXT:
  405. widget = AddText(property);
  406. break;
  407. case OBS_PROPERTY_PATH:
  408. AddPath(property, layout, &label);
  409. break;
  410. case OBS_PROPERTY_LIST:
  411. widget = AddList(property, warning);
  412. break;
  413. case OBS_PROPERTY_COLOR:
  414. AddColor(property, layout, label);
  415. break;
  416. case OBS_PROPERTY_FONT:
  417. AddFont(property, layout, label);
  418. break;
  419. case OBS_PROPERTY_BUTTON:
  420. widget = AddButton(property);
  421. break;
  422. }
  423. if (widget && !obs_property_enabled(property))
  424. widget->setEnabled(false);
  425. if (!label &&
  426. type != OBS_PROPERTY_BOOL &&
  427. type != OBS_PROPERTY_BUTTON)
  428. label = new QLabel(QT_UTF8(obs_property_description(property)));
  429. if (warning && label) //TODO: select color based on background color
  430. label->setStyleSheet("QLabel { color: red; }");
  431. if (label && minSize) {
  432. label->setMinimumWidth(minSize);
  433. label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  434. }
  435. if (!widget)
  436. return;
  437. layout->addRow(label, widget);
  438. if (!lastFocused.empty())
  439. if (lastFocused.compare(name) == 0)
  440. lastWidget = widget;
  441. }
  442. void OBSPropertiesView::SignalChanged()
  443. {
  444. emit Changed();
  445. }
  446. void WidgetInfo::BoolChanged(const char *setting)
  447. {
  448. QCheckBox *checkbox = static_cast<QCheckBox*>(widget);
  449. obs_data_set_bool(view->settings, setting,
  450. checkbox->checkState() == Qt::Checked);
  451. }
  452. void WidgetInfo::IntChanged(const char *setting)
  453. {
  454. QSpinBox *spin = static_cast<QSpinBox*>(widget);
  455. obs_data_set_int(view->settings, setting, spin->value());
  456. }
  457. void WidgetInfo::FloatChanged(const char *setting)
  458. {
  459. QDoubleSpinBox *spin = static_cast<QDoubleSpinBox*>(widget);
  460. obs_data_set_double(view->settings, setting, spin->value());
  461. }
  462. void WidgetInfo::TextChanged(const char *setting)
  463. {
  464. obs_text_type type = obs_proprety_text_type(property);
  465. if (type == OBS_TEXT_MULTILINE) {
  466. QPlainTextEdit *edit = static_cast<QPlainTextEdit*>(widget);
  467. obs_data_set_string(view->settings, setting,
  468. QT_TO_UTF8(edit->toPlainText()));
  469. return;
  470. }
  471. QLineEdit *edit = static_cast<QLineEdit*>(widget);
  472. obs_data_set_string(view->settings, setting, QT_TO_UTF8(edit->text()));
  473. }
  474. bool WidgetInfo::PathChanged(const char *setting)
  475. {
  476. const char *desc = obs_property_description(property);
  477. obs_path_type type = obs_property_path_type(property);
  478. const char *filter = obs_property_path_filter(property);
  479. const char *default_path = obs_property_path_default_path(property);
  480. QString path;
  481. if (type == OBS_PATH_DIRECTORY)
  482. path = QFileDialog::getExistingDirectory(view,
  483. QT_UTF8(desc), QT_UTF8(default_path),
  484. QFileDialog::ShowDirsOnly |
  485. QFileDialog::DontResolveSymlinks);
  486. else if (type == OBS_PATH_FILE)
  487. path = QFileDialog::getOpenFileName(view,
  488. QT_UTF8(desc), QT_UTF8(default_path),
  489. QT_UTF8(filter));
  490. if (path.isEmpty())
  491. return false;
  492. QLineEdit *edit = static_cast<QLineEdit*>(widget);
  493. edit->setText(path);
  494. obs_data_set_string(view->settings, setting, QT_TO_UTF8(path));
  495. return true;
  496. }
  497. void WidgetInfo::ListChanged(const char *setting)
  498. {
  499. QComboBox *combo = static_cast<QComboBox*>(widget);
  500. obs_combo_format format = obs_property_list_format(property);
  501. obs_combo_type type = obs_property_list_type(property);
  502. QVariant data;
  503. if (type == OBS_COMBO_TYPE_EDITABLE) {
  504. data = combo->currentText();
  505. } else {
  506. int index = combo->currentIndex();
  507. if (index != -1)
  508. data = combo->itemData(index);
  509. else
  510. return;
  511. }
  512. switch (format) {
  513. case OBS_COMBO_FORMAT_INVALID:
  514. return;
  515. case OBS_COMBO_FORMAT_INT:
  516. obs_data_set_int(view->settings, setting,
  517. data.value<long long>());
  518. break;
  519. case OBS_COMBO_FORMAT_FLOAT:
  520. obs_data_set_double(view->settings, setting,
  521. data.value<double>());
  522. break;
  523. case OBS_COMBO_FORMAT_STRING:
  524. obs_data_set_string(view->settings, setting,
  525. QT_TO_UTF8(data.toString()));
  526. break;
  527. }
  528. }
  529. bool WidgetInfo::ColorChanged(const char *setting)
  530. {
  531. const char *desc = obs_property_description(property);
  532. long long val = obs_data_get_int(view->settings, setting);
  533. QColor color = color_from_int(val);
  534. QColorDialog::ColorDialogOptions options =
  535. QColorDialog::ShowAlphaChannel;
  536. /* The native dialog on OSX has all kinds of problems, like closing
  537. * other open QDialogs on exit, and
  538. * https://bugreports.qt-project.org/browse/QTBUG-34532
  539. */
  540. #ifdef __APPLE__
  541. options |= QColorDialog::DontUseNativeDialog;
  542. #endif
  543. color = QColorDialog::getColor(color, view, QT_UTF8(desc), options);
  544. if (!color.isValid())
  545. return false;
  546. QLabel *label = static_cast<QLabel*>(widget);
  547. label->setText(color.name(QColor::HexArgb));
  548. label->setPalette(QPalette(color));
  549. obs_data_set_int(view->settings, setting, color_to_int(color));
  550. return true;
  551. }
  552. bool WidgetInfo::FontChanged(const char *setting)
  553. {
  554. obs_data_t *font_obj = obs_data_get_obj(view->settings, setting);
  555. bool success;
  556. uint32_t flags;
  557. QFont font;
  558. if (!font_obj) {
  559. font = QFontDialog::getFont(&success, view);
  560. } else {
  561. MakeQFont(font_obj, font);
  562. font = QFontDialog::getFont(&success, font, view);
  563. obs_data_release(font_obj);
  564. }
  565. if (!success)
  566. return false;
  567. font_obj = obs_data_create();
  568. obs_data_set_string(font_obj, "face", QT_TO_UTF8(font.family()));
  569. obs_data_set_string(font_obj, "style", QT_TO_UTF8(font.styleName()));
  570. obs_data_set_int(font_obj, "size", font.pointSize());
  571. flags = font.bold() ? OBS_FONT_BOLD : 0;
  572. flags |= font.italic() ? OBS_FONT_ITALIC : 0;
  573. flags |= font.underline() ? OBS_FONT_UNDERLINE : 0;
  574. flags |= font.strikeOut() ? OBS_FONT_STRIKEOUT : 0;
  575. obs_data_set_int(font_obj, "flags", flags);
  576. QLabel *label = static_cast<QLabel*>(widget);
  577. label->setFont(font);
  578. label->setText(QString("%1 %2").arg(font.family(), font.styleName()));
  579. obs_data_set_obj(view->settings, setting, font_obj);
  580. obs_data_release(font_obj);
  581. return true;
  582. }
  583. void WidgetInfo::ButtonClicked()
  584. {
  585. if (obs_property_button_clicked(property, view->obj)) {
  586. QMetaObject::invokeMethod(view, "RefreshProperties",
  587. Qt::QueuedConnection);
  588. }
  589. }
  590. void WidgetInfo::ControlChanged()
  591. {
  592. const char *setting = obs_property_name(property);
  593. obs_property_type type = obs_property_get_type(property);
  594. switch (type) {
  595. case OBS_PROPERTY_INVALID: return;
  596. case OBS_PROPERTY_BOOL: BoolChanged(setting); break;
  597. case OBS_PROPERTY_INT: IntChanged(setting); break;
  598. case OBS_PROPERTY_FLOAT: FloatChanged(setting); break;
  599. case OBS_PROPERTY_TEXT: TextChanged(setting); break;
  600. case OBS_PROPERTY_LIST: ListChanged(setting); break;
  601. case OBS_PROPERTY_BUTTON: ButtonClicked(); return;
  602. case OBS_PROPERTY_COLOR:
  603. if (!ColorChanged(setting))
  604. return;
  605. break;
  606. case OBS_PROPERTY_FONT:
  607. if (!FontChanged(setting))
  608. return;
  609. break;
  610. case OBS_PROPERTY_PATH:
  611. if (!PathChanged(setting))
  612. return;
  613. }
  614. if (view->callback)
  615. view->callback(view->obj, view->settings);
  616. view->SignalChanged();
  617. if (obs_property_modified(property, view->settings)) {
  618. view->lastFocused = setting;
  619. QMetaObject::invokeMethod(view, "RefreshProperties",
  620. Qt::QueuedConnection);
  621. }
  622. }