1
0

obs-properties.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. /******************************************************************************
  2. Copyright (C) 2014 by Hugh Bailey <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. #include "util/bmem.h"
  15. #include "util/darray.h"
  16. #include "obs-internal.h"
  17. #include "obs-properties.h"
  18. static inline void *get_property_data(struct obs_property *prop);
  19. /* ------------------------------------------------------------------------- */
  20. struct float_data {
  21. double min, max, step;
  22. enum obs_number_type type;
  23. };
  24. struct int_data {
  25. int min, max, step;
  26. enum obs_number_type type;
  27. };
  28. struct list_item {
  29. char *name;
  30. bool disabled;
  31. union {
  32. char *str;
  33. long long ll;
  34. double d;
  35. };
  36. };
  37. struct path_data {
  38. char *filter;
  39. char *default_path;
  40. enum obs_path_type type;
  41. };
  42. struct text_data {
  43. enum obs_text_type type;
  44. };
  45. struct list_data {
  46. DARRAY(struct list_item) items;
  47. enum obs_combo_type type;
  48. enum obs_combo_format format;
  49. };
  50. struct editable_list_data {
  51. enum obs_editable_list_type type;
  52. char *filter;
  53. char *default_path;
  54. };
  55. struct button_data {
  56. obs_property_clicked_t callback;
  57. };
  58. struct frame_rate_option {
  59. char *name;
  60. char *description;
  61. };
  62. struct frame_rate_range {
  63. struct media_frames_per_second min_time;
  64. struct media_frames_per_second max_time;
  65. };
  66. struct frame_rate_data {
  67. DARRAY(struct frame_rate_option) extra_options;
  68. DARRAY(struct frame_rate_range) ranges;
  69. };
  70. struct group_data {
  71. enum obs_group_type type;
  72. obs_properties_t *content;
  73. };
  74. static inline void path_data_free(struct path_data *data)
  75. {
  76. bfree(data->default_path);
  77. if (data->type == OBS_PATH_FILE)
  78. bfree(data->filter);
  79. }
  80. static inline void editable_list_data_free(struct editable_list_data *data)
  81. {
  82. bfree(data->default_path);
  83. bfree(data->filter);
  84. }
  85. static inline void list_item_free(struct list_data *data,
  86. struct list_item *item)
  87. {
  88. bfree(item->name);
  89. if (data->format == OBS_COMBO_FORMAT_STRING)
  90. bfree(item->str);
  91. }
  92. static inline void list_data_free(struct list_data *data)
  93. {
  94. for (size_t i = 0; i < data->items.num; i++)
  95. list_item_free(data, data->items.array+i);
  96. da_free(data->items);
  97. }
  98. static inline void frame_rate_data_options_free(struct frame_rate_data *data)
  99. {
  100. for (size_t i = 0; i < data->extra_options.num; i++) {
  101. struct frame_rate_option *opt = &data->extra_options.array[i];
  102. bfree(opt->name);
  103. bfree(opt->description);
  104. }
  105. da_resize(data->extra_options, 0);
  106. }
  107. static inline void frame_rate_data_ranges_free(struct frame_rate_data *data)
  108. {
  109. da_resize(data->ranges, 0);
  110. }
  111. static inline void frame_rate_data_free(struct frame_rate_data *data)
  112. {
  113. frame_rate_data_options_free(data);
  114. frame_rate_data_ranges_free(data);
  115. da_free(data->extra_options);
  116. da_free(data->ranges);
  117. }
  118. static inline void group_data_free(struct group_data *data) {
  119. obs_properties_destroy(data->content);
  120. }
  121. struct obs_properties;
  122. struct obs_property {
  123. char *name;
  124. char *desc;
  125. char *long_desc;
  126. void *priv;
  127. enum obs_property_type type;
  128. bool visible;
  129. bool enabled;
  130. struct obs_properties *parent;
  131. obs_property_modified_t modified;
  132. obs_property_modified2_t modified2;
  133. struct obs_property *next;
  134. };
  135. struct obs_properties {
  136. void *param;
  137. void (*destroy)(void *param);
  138. uint32_t flags;
  139. struct obs_property *first_property;
  140. struct obs_property **last;
  141. struct obs_property *parent;
  142. };
  143. obs_properties_t *obs_properties_create(void)
  144. {
  145. struct obs_properties *props;
  146. props = bzalloc(sizeof(struct obs_properties));
  147. props->last = &props->first_property;
  148. return props;
  149. }
  150. void obs_properties_set_param(obs_properties_t *props,
  151. void *param, void (*destroy)(void *param))
  152. {
  153. if (!props)
  154. return;
  155. if (props->param && props->destroy)
  156. props->destroy(props->param);
  157. props->param = param;
  158. props->destroy = destroy;
  159. }
  160. void obs_properties_set_flags(obs_properties_t *props, uint32_t flags)
  161. {
  162. if (props)
  163. props->flags = flags;
  164. }
  165. uint32_t obs_properties_get_flags(obs_properties_t *props)
  166. {
  167. return props ? props->flags : 0;
  168. }
  169. void *obs_properties_get_param(obs_properties_t *props)
  170. {
  171. return props ? props->param : NULL;
  172. }
  173. obs_properties_t *obs_properties_create_param(void *param,
  174. void (*destroy)(void *param))
  175. {
  176. struct obs_properties *props = obs_properties_create();
  177. obs_properties_set_param(props, param, destroy);
  178. return props;
  179. }
  180. static void obs_property_destroy(struct obs_property *property)
  181. {
  182. if (property->type == OBS_PROPERTY_LIST)
  183. list_data_free(get_property_data(property));
  184. else if (property->type == OBS_PROPERTY_PATH)
  185. path_data_free(get_property_data(property));
  186. else if (property->type == OBS_PROPERTY_EDITABLE_LIST)
  187. editable_list_data_free(get_property_data(property));
  188. else if (property->type == OBS_PROPERTY_FRAME_RATE)
  189. frame_rate_data_free(get_property_data(property));
  190. else if (property->type == OBS_PROPERTY_GROUP)
  191. group_data_free(get_property_data(property));
  192. bfree(property->name);
  193. bfree(property->desc);
  194. bfree(property->long_desc);
  195. bfree(property);
  196. }
  197. void obs_properties_destroy(obs_properties_t *props)
  198. {
  199. if (props) {
  200. struct obs_property *p = props->first_property;
  201. if (props->destroy && props->param)
  202. props->destroy(props->param);
  203. while (p) {
  204. struct obs_property *next = p->next;
  205. obs_property_destroy(p);
  206. p = next;
  207. }
  208. bfree(props);
  209. }
  210. }
  211. obs_property_t *obs_properties_first(obs_properties_t *props)
  212. {
  213. return (props != NULL) ? props->first_property : NULL;
  214. }
  215. obs_property_t *obs_properties_get(obs_properties_t *props, const char *name)
  216. {
  217. struct obs_property *property;
  218. if (!props)
  219. return NULL;
  220. property = props->first_property;
  221. while (property) {
  222. if (strcmp(property->name, name) == 0)
  223. return property;
  224. if (property->type == OBS_PROPERTY_GROUP) {
  225. obs_properties_t *group =
  226. obs_property_group_content(property);
  227. obs_property_t *found = obs_properties_get(group, name);
  228. if (found != NULL) {
  229. return found;
  230. }
  231. }
  232. property = property->next;
  233. }
  234. return NULL;
  235. }
  236. obs_properties_t *obs_properties_get_parent(obs_properties_t *props)
  237. {
  238. return props->parent ? props->parent->parent : NULL;
  239. }
  240. void obs_properties_remove_by_name(obs_properties_t *props, const char *name)
  241. {
  242. if (!props)
  243. return;
  244. /* obs_properties_t is a forward-linked-list, so we need to keep both
  245. * previous and current pointers around. That way we can fix up the
  246. * pointers for the previous element if we find a match.
  247. */
  248. struct obs_property *cur = props->first_property;
  249. struct obs_property *prev = props->first_property;
  250. while (cur) {
  251. if (strcmp(cur->name, name) == 0) {
  252. prev->next = cur->next;
  253. cur->next = 0;
  254. obs_property_destroy(cur);
  255. break;
  256. }
  257. prev = cur;
  258. cur = cur->next;
  259. }
  260. }
  261. void obs_properties_apply_settings(obs_properties_t *props, obs_data_t *settings)
  262. {
  263. struct obs_property *p;
  264. if (!props)
  265. return;
  266. p = props->first_property;
  267. while (p) {
  268. if (p->modified)
  269. p->modified(props, p, settings);
  270. else if (p->modified2)
  271. p->modified2(p->priv, props, p, settings);
  272. p = p->next;
  273. }
  274. }
  275. /* ------------------------------------------------------------------------- */
  276. static inline void propertes_add(struct obs_properties *props,
  277. struct obs_property *p)
  278. {
  279. *props->last = p;
  280. props->last = &p->next;
  281. }
  282. static inline size_t get_property_size(enum obs_property_type type)
  283. {
  284. switch (type) {
  285. case OBS_PROPERTY_INVALID: return 0;
  286. case OBS_PROPERTY_BOOL: return 0;
  287. case OBS_PROPERTY_INT: return sizeof(struct int_data);
  288. case OBS_PROPERTY_FLOAT: return sizeof(struct float_data);
  289. case OBS_PROPERTY_TEXT: return sizeof(struct text_data);
  290. case OBS_PROPERTY_PATH: return sizeof(struct path_data);
  291. case OBS_PROPERTY_LIST: return sizeof(struct list_data);
  292. case OBS_PROPERTY_COLOR: return 0;
  293. case OBS_PROPERTY_BUTTON: return sizeof(struct button_data);
  294. case OBS_PROPERTY_FONT: return 0;
  295. case OBS_PROPERTY_EDITABLE_LIST:
  296. return sizeof(struct editable_list_data);
  297. case OBS_PROPERTY_FRAME_RATE:return sizeof(struct frame_rate_data);
  298. case OBS_PROPERTY_GROUP: return sizeof(struct group_data);
  299. }
  300. return 0;
  301. }
  302. static inline struct obs_property *new_prop(struct obs_properties *props,
  303. const char *name, const char *desc,
  304. enum obs_property_type type)
  305. {
  306. size_t data_size = get_property_size(type);
  307. struct obs_property *p;
  308. p = bzalloc(sizeof(struct obs_property) + data_size);
  309. p->parent = props;
  310. p->enabled = true;
  311. p->visible = true;
  312. p->type = type;
  313. p->name = bstrdup(name);
  314. p->desc = bstrdup(desc);
  315. propertes_add(props, p);
  316. return p;
  317. }
  318. static inline obs_properties_t *get_topmost_parent(obs_properties_t *props)
  319. {
  320. obs_properties_t *parent = props;
  321. obs_properties_t *last_parent = parent;
  322. while (parent) {
  323. last_parent = parent;
  324. parent = obs_properties_get_parent(parent);
  325. }
  326. return last_parent;
  327. }
  328. static inline bool contains_prop(struct obs_properties *props, const char *name)
  329. {
  330. struct obs_property *p = props->first_property;
  331. while (p) {
  332. if (strcmp(p->name, name) == 0) {
  333. blog(LOG_WARNING, "Property '%s' exists", name);
  334. return true;
  335. }
  336. if (p->type == OBS_PROPERTY_GROUP) {
  337. if (contains_prop(obs_property_group_content(p), name)) {
  338. return true;
  339. }
  340. }
  341. p = p->next;
  342. }
  343. return false;
  344. }
  345. static inline bool has_prop(struct obs_properties *props, const char *name)
  346. {
  347. return contains_prop(get_topmost_parent(props), name);
  348. }
  349. static inline void *get_property_data(struct obs_property *prop)
  350. {
  351. return (uint8_t*)prop + sizeof(struct obs_property);
  352. }
  353. static inline void *get_type_data(struct obs_property *prop,
  354. enum obs_property_type type)
  355. {
  356. if (!prop || prop->type != type)
  357. return NULL;
  358. return get_property_data(prop);
  359. }
  360. obs_property_t *obs_properties_add_bool(obs_properties_t *props,
  361. const char *name, const char *desc)
  362. {
  363. if (!props || has_prop(props, name)) return NULL;
  364. return new_prop(props, name, desc, OBS_PROPERTY_BOOL);
  365. }
  366. static obs_property_t *add_int(obs_properties_t *props,
  367. const char *name, const char *desc, int min, int max, int step,
  368. enum obs_number_type type)
  369. {
  370. if (!props || has_prop(props, name)) return NULL;
  371. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_INT);
  372. struct int_data *data = get_property_data(p);
  373. data->min = min;
  374. data->max = max;
  375. data->step = step;
  376. data->type = type;
  377. return p;
  378. }
  379. static obs_property_t *add_flt(obs_properties_t *props,
  380. const char *name, const char *desc,
  381. double min, double max, double step,
  382. enum obs_number_type type)
  383. {
  384. if (!props || has_prop(props, name)) return NULL;
  385. struct obs_property *p = new_prop(props, name, desc,
  386. OBS_PROPERTY_FLOAT);
  387. struct float_data *data = get_property_data(p);
  388. data->min = min;
  389. data->max = max;
  390. data->step = step;
  391. data->type = type;
  392. return p;
  393. }
  394. obs_property_t *obs_properties_add_int(obs_properties_t *props,
  395. const char *name, const char *desc, int min, int max, int step)
  396. {
  397. return add_int(props, name, desc, min, max, step, OBS_NUMBER_SCROLLER);
  398. }
  399. obs_property_t *obs_properties_add_float(obs_properties_t *props,
  400. const char *name, const char *desc,
  401. double min, double max, double step)
  402. {
  403. return add_flt(props, name, desc, min, max, step, OBS_NUMBER_SCROLLER);
  404. }
  405. obs_property_t *obs_properties_add_int_slider(obs_properties_t *props,
  406. const char *name, const char *desc, int min, int max, int step)
  407. {
  408. return add_int(props, name, desc, min, max, step, OBS_NUMBER_SLIDER);
  409. }
  410. obs_property_t *obs_properties_add_float_slider(obs_properties_t *props,
  411. const char *name, const char *desc,
  412. double min, double max, double step)
  413. {
  414. return add_flt(props, name, desc, min, max, step, OBS_NUMBER_SLIDER);
  415. }
  416. obs_property_t *obs_properties_add_text(obs_properties_t *props,
  417. const char *name, const char *desc, enum obs_text_type type)
  418. {
  419. if (!props || has_prop(props, name)) return NULL;
  420. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_TEXT);
  421. struct text_data *data = get_property_data(p);
  422. data->type = type;
  423. return p;
  424. }
  425. obs_property_t *obs_properties_add_path(obs_properties_t *props,
  426. const char *name, const char *desc, enum obs_path_type type,
  427. const char *filter, const char *default_path)
  428. {
  429. if (!props || has_prop(props, name)) return NULL;
  430. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_PATH);
  431. struct path_data *data = get_property_data(p);
  432. data->type = type;
  433. data->default_path = bstrdup(default_path);
  434. if (data->type == OBS_PATH_FILE)
  435. data->filter = bstrdup(filter);
  436. return p;
  437. }
  438. obs_property_t *obs_properties_add_list(obs_properties_t *props,
  439. const char *name, const char *desc,
  440. enum obs_combo_type type,
  441. enum obs_combo_format format)
  442. {
  443. if (!props || has_prop(props, name)) return NULL;
  444. if (type == OBS_COMBO_TYPE_EDITABLE &&
  445. format != OBS_COMBO_FORMAT_STRING) {
  446. blog(LOG_WARNING, "List '%s', error: Editable combo boxes "
  447. "must be of the 'string' type", name);
  448. return NULL;
  449. }
  450. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_LIST);
  451. struct list_data *data = get_property_data(p);
  452. data->format = format;
  453. data->type = type;
  454. return p;
  455. }
  456. obs_property_t *obs_properties_add_color(obs_properties_t *props,
  457. const char *name, const char *desc)
  458. {
  459. if (!props || has_prop(props, name)) return NULL;
  460. return new_prop(props, name, desc, OBS_PROPERTY_COLOR);
  461. }
  462. obs_property_t *obs_properties_add_button(obs_properties_t *props,
  463. const char *name, const char *text,
  464. obs_property_clicked_t callback)
  465. {
  466. if (!props || has_prop(props, name)) return NULL;
  467. struct obs_property *p = new_prop(props, name, text,
  468. OBS_PROPERTY_BUTTON);
  469. struct button_data *data = get_property_data(p);
  470. data->callback = callback;
  471. return p;
  472. }
  473. obs_property_t *obs_properties_add_button2(obs_properties_t *props,
  474. const char *name, const char *text,
  475. obs_property_clicked_t callback, void *priv)
  476. {
  477. if (!props || has_prop(props, name)) return NULL;
  478. struct obs_property *p = new_prop(props, name, text,
  479. OBS_PROPERTY_BUTTON);
  480. struct button_data *data = get_property_data(p);
  481. data->callback = callback;
  482. p->priv = priv;
  483. return p;
  484. }
  485. obs_property_t *obs_properties_add_font(obs_properties_t *props,
  486. const char *name, const char *desc)
  487. {
  488. if (!props || has_prop(props, name)) return NULL;
  489. return new_prop(props, name, desc, OBS_PROPERTY_FONT);
  490. }
  491. obs_property_t *obs_properties_add_editable_list(obs_properties_t *props,
  492. const char *name, const char *desc,
  493. enum obs_editable_list_type type, const char *filter,
  494. const char *default_path)
  495. {
  496. if (!props || has_prop(props, name)) return NULL;
  497. struct obs_property *p = new_prop(props, name, desc,
  498. OBS_PROPERTY_EDITABLE_LIST);
  499. struct editable_list_data *data = get_property_data(p);
  500. data->type = type;
  501. data->filter = bstrdup(filter);
  502. data->default_path = bstrdup(default_path);
  503. return p;
  504. }
  505. obs_property_t *obs_properties_add_frame_rate(obs_properties_t *props,
  506. const char *name, const char *desc)
  507. {
  508. if (!props || has_prop(props, name)) return NULL;
  509. struct obs_property *p = new_prop(props, name, desc,
  510. OBS_PROPERTY_FRAME_RATE);
  511. struct frame_rate_data *data = get_property_data(p);
  512. da_init(data->extra_options);
  513. da_init(data->ranges);
  514. return p;
  515. }
  516. static bool check_property_group_recursion(obs_properties_t *parent,
  517. obs_properties_t *group)
  518. {
  519. /* Scan the group for the parent. */
  520. obs_property_t *current_property = group->first_property;
  521. while (current_property) {
  522. if (current_property->type == OBS_PROPERTY_GROUP) {
  523. obs_properties_t *cprops =
  524. obs_property_group_content(current_property);
  525. if (cprops == parent) {
  526. /* Contains find_props */
  527. return true;
  528. } else if (cprops == group) {
  529. /* Contains self, shouldn't be possible but
  530. * lets verify anyway. */
  531. return true;
  532. }
  533. check_property_group_recursion(cprops, group);
  534. }
  535. current_property = current_property->next;
  536. }
  537. return false;
  538. }
  539. static bool check_property_group_duplicates(obs_properties_t *parent,
  540. obs_properties_t *group)
  541. {
  542. obs_property_t *current_property = group->first_property;
  543. while (current_property) {
  544. if (has_prop(parent, current_property->name)) {
  545. return true;
  546. }
  547. current_property = current_property->next;
  548. }
  549. return false;
  550. }
  551. obs_property_t *obs_properties_add_group(obs_properties_t *props,
  552. const char *name, const char *desc, enum obs_group_type type,
  553. obs_properties_t *group)
  554. {
  555. if (!props || has_prop(props, name)) return NULL;
  556. if (!group) return NULL;
  557. /* Prevent recursion. */
  558. if (props == group) return NULL;
  559. if (check_property_group_recursion(props, group)) return NULL;
  560. /* Prevent duplicate properties */
  561. if (check_property_group_duplicates(props, group)) return NULL;
  562. obs_property_t *p = new_prop(props, name, desc, OBS_PROPERTY_GROUP);
  563. group->parent = p;
  564. struct group_data *data = get_property_data(p);
  565. data->type = type;
  566. data->content = group;
  567. return p;
  568. }
  569. /* ------------------------------------------------------------------------- */
  570. static inline bool is_combo(struct obs_property *p)
  571. {
  572. return p->type == OBS_PROPERTY_LIST;
  573. }
  574. static inline struct list_data *get_list_data(struct obs_property *p)
  575. {
  576. if (!p || !is_combo(p))
  577. return NULL;
  578. return get_property_data(p);
  579. }
  580. static inline struct list_data *get_list_fmt_data(struct obs_property *p,
  581. enum obs_combo_format format)
  582. {
  583. struct list_data *data = get_list_data(p);
  584. return (data && data->format == format) ? data : NULL;
  585. }
  586. /* ------------------------------------------------------------------------- */
  587. bool obs_property_next(obs_property_t **p)
  588. {
  589. if (!p || !*p)
  590. return false;
  591. *p = (*p)->next;
  592. return *p != NULL;
  593. }
  594. void obs_property_set_modified_callback(obs_property_t *p,
  595. obs_property_modified_t modified)
  596. {
  597. if (p) p->modified = modified;
  598. }
  599. void obs_property_set_modified_callback2(obs_property_t *p,
  600. obs_property_modified2_t modified2, void *priv)
  601. {
  602. if (p) {
  603. p->modified2 = modified2;
  604. p->priv = priv;
  605. }
  606. }
  607. bool obs_property_modified(obs_property_t *p, obs_data_t *settings)
  608. {
  609. if (p) {
  610. if (p->modified) {
  611. obs_properties_t *top = get_topmost_parent(p->parent);
  612. return p->modified(top, p, settings);
  613. } else if (p->modified2) {
  614. obs_properties_t *top = get_topmost_parent(p->parent);
  615. return p->modified2(p->priv, top, p, settings);
  616. }
  617. }
  618. return false;
  619. }
  620. bool obs_property_button_clicked(obs_property_t *p, void *obj)
  621. {
  622. struct obs_context_data *context = obj;
  623. if (p) {
  624. struct button_data *data = get_type_data(p,
  625. OBS_PROPERTY_BUTTON);
  626. if (data && data->callback) {
  627. obs_properties_t *top = get_topmost_parent(p->parent);
  628. if (p->priv)
  629. return data->callback(top, p, p->priv);
  630. return data->callback(top, p,
  631. (context ? context->data : NULL));
  632. }
  633. }
  634. return false;
  635. }
  636. void obs_property_set_visible(obs_property_t *p, bool visible)
  637. {
  638. if (p) p->visible = visible;
  639. }
  640. void obs_property_set_enabled(obs_property_t *p, bool enabled)
  641. {
  642. if (p) p->enabled = enabled;
  643. }
  644. void obs_property_set_description(obs_property_t *p, const char *description)
  645. {
  646. if (p) {
  647. bfree(p->desc);
  648. p->desc = description && *description
  649. ? bstrdup(description)
  650. : NULL;
  651. }
  652. }
  653. void obs_property_set_long_description(obs_property_t *p, const char *long_desc)
  654. {
  655. if (p) {
  656. bfree(p->long_desc);
  657. p->long_desc = long_desc && *long_desc
  658. ? bstrdup(long_desc)
  659. : NULL;
  660. }
  661. }
  662. const char *obs_property_name(obs_property_t *p)
  663. {
  664. return p ? p->name : NULL;
  665. }
  666. const char *obs_property_description(obs_property_t *p)
  667. {
  668. return p ? p->desc : NULL;
  669. }
  670. const char *obs_property_long_description(obs_property_t *p)
  671. {
  672. return p ? p->long_desc : NULL;
  673. }
  674. enum obs_property_type obs_property_get_type(obs_property_t *p)
  675. {
  676. return p ? p->type : OBS_PROPERTY_INVALID;
  677. }
  678. bool obs_property_enabled(obs_property_t *p)
  679. {
  680. return p ? p->enabled : false;
  681. }
  682. bool obs_property_visible(obs_property_t *p)
  683. {
  684. return p ? p->visible : false;
  685. }
  686. int obs_property_int_min(obs_property_t *p)
  687. {
  688. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  689. return data ? data->min : 0;
  690. }
  691. int obs_property_int_max(obs_property_t *p)
  692. {
  693. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  694. return data ? data->max : 0;
  695. }
  696. int obs_property_int_step(obs_property_t *p)
  697. {
  698. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  699. return data ? data->step : 0;
  700. }
  701. enum obs_number_type obs_property_int_type(obs_property_t *p)
  702. {
  703. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  704. return data ? data->type : OBS_NUMBER_SCROLLER;
  705. }
  706. double obs_property_float_min(obs_property_t *p)
  707. {
  708. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  709. return data ? data->min : 0;
  710. }
  711. double obs_property_float_max(obs_property_t *p)
  712. {
  713. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  714. return data ? data->max : 0;
  715. }
  716. double obs_property_float_step(obs_property_t *p)
  717. {
  718. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  719. return data ? data->step : 0;
  720. }
  721. enum obs_number_type obs_property_float_type(obs_property_t *p)
  722. {
  723. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  724. return data ? data->type : OBS_NUMBER_SCROLLER;
  725. }
  726. enum obs_text_type obs_property_text_type(obs_property_t *p)
  727. {
  728. struct text_data *data = get_type_data(p, OBS_PROPERTY_TEXT);
  729. return data ? data->type : OBS_TEXT_DEFAULT;
  730. }
  731. enum obs_path_type obs_property_path_type(obs_property_t *p)
  732. {
  733. struct path_data *data = get_type_data(p, OBS_PROPERTY_PATH);
  734. return data ? data->type : OBS_PATH_DIRECTORY;
  735. }
  736. const char *obs_property_path_filter(obs_property_t *p)
  737. {
  738. struct path_data *data = get_type_data(p, OBS_PROPERTY_PATH);
  739. return data ? data->filter : NULL;
  740. }
  741. const char *obs_property_path_default_path(obs_property_t *p)
  742. {
  743. struct path_data *data = get_type_data(p, OBS_PROPERTY_PATH);
  744. return data ? data->default_path : NULL;
  745. }
  746. enum obs_combo_type obs_property_list_type(obs_property_t *p)
  747. {
  748. struct list_data *data = get_list_data(p);
  749. return data ? data->type : OBS_COMBO_TYPE_INVALID;
  750. }
  751. enum obs_combo_format obs_property_list_format(obs_property_t *p)
  752. {
  753. struct list_data *data = get_list_data(p);
  754. return data ? data->format : OBS_COMBO_FORMAT_INVALID;
  755. }
  756. void obs_property_int_set_limits(obs_property_t *p,
  757. int min, int max, int step)
  758. {
  759. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  760. if (!data)
  761. return;
  762. data->min = min;
  763. data->max = max;
  764. data->step = step;
  765. }
  766. void obs_property_float_set_limits(obs_property_t *p,
  767. double min, double max, double step)
  768. {
  769. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  770. if (!data)
  771. return;
  772. data->min = min;
  773. data->max = max;
  774. data->step = step;
  775. }
  776. void obs_property_list_clear(obs_property_t *p)
  777. {
  778. struct list_data *data = get_list_data(p);
  779. if (data)
  780. list_data_free(data);
  781. }
  782. static size_t add_item(struct list_data *data, const char *name,
  783. const void *val)
  784. {
  785. struct list_item item = { NULL };
  786. item.name = bstrdup(name);
  787. if (data->format == OBS_COMBO_FORMAT_INT)
  788. item.ll = *(const long long*)val;
  789. else if (data->format == OBS_COMBO_FORMAT_FLOAT)
  790. item.d = *(const double*)val;
  791. else
  792. item.str = bstrdup(val);
  793. return da_push_back(data->items, &item);
  794. }
  795. static void insert_item(struct list_data *data, size_t idx, const char *name,
  796. const void *val)
  797. {
  798. struct list_item item = { NULL };
  799. item.name = bstrdup(name);
  800. if (data->format == OBS_COMBO_FORMAT_INT)
  801. item.ll = *(const long long*)val;
  802. else if (data->format == OBS_COMBO_FORMAT_FLOAT)
  803. item.d = *(const double*)val;
  804. else
  805. item.str = bstrdup(val);
  806. da_insert(data->items, idx, &item);
  807. }
  808. size_t obs_property_list_add_string(obs_property_t *p,
  809. const char *name, const char *val)
  810. {
  811. struct list_data *data = get_list_data(p);
  812. if (data && data->format == OBS_COMBO_FORMAT_STRING)
  813. return add_item(data, name, val);
  814. return 0;
  815. }
  816. size_t obs_property_list_add_int(obs_property_t *p,
  817. const char *name, long long val)
  818. {
  819. struct list_data *data = get_list_data(p);
  820. if (data && data->format == OBS_COMBO_FORMAT_INT)
  821. return add_item(data, name, &val);
  822. return 0;
  823. }
  824. size_t obs_property_list_add_float(obs_property_t *p,
  825. const char *name, double val)
  826. {
  827. struct list_data *data = get_list_data(p);
  828. if (data && data->format == OBS_COMBO_FORMAT_FLOAT)
  829. return add_item(data, name, &val);
  830. return 0;
  831. }
  832. void obs_property_list_insert_string(obs_property_t *p, size_t idx,
  833. const char *name, const char *val)
  834. {
  835. struct list_data *data = get_list_data(p);
  836. if (data && data->format == OBS_COMBO_FORMAT_STRING)
  837. insert_item(data, idx, name, val);
  838. }
  839. void obs_property_list_insert_int(obs_property_t *p, size_t idx,
  840. const char *name, long long val)
  841. {
  842. struct list_data *data = get_list_data(p);
  843. if (data && data->format == OBS_COMBO_FORMAT_INT)
  844. insert_item(data, idx, name, &val);
  845. }
  846. void obs_property_list_insert_float(obs_property_t *p, size_t idx,
  847. const char *name, double val)
  848. {
  849. struct list_data *data = get_list_data(p);
  850. if (data && data->format == OBS_COMBO_FORMAT_FLOAT)
  851. insert_item(data, idx, name, &val);
  852. }
  853. void obs_property_list_item_remove(obs_property_t *p, size_t idx)
  854. {
  855. struct list_data *data = get_list_data(p);
  856. if (data && idx < data->items.num) {
  857. list_item_free(data, data->items.array+idx);
  858. da_erase(data->items, idx);
  859. }
  860. }
  861. size_t obs_property_list_item_count(obs_property_t *p)
  862. {
  863. struct list_data *data = get_list_data(p);
  864. return data ? data->items.num : 0;
  865. }
  866. bool obs_property_list_item_disabled(obs_property_t *p, size_t idx)
  867. {
  868. struct list_data *data = get_list_data(p);
  869. return (data && idx < data->items.num) ?
  870. data->items.array[idx].disabled : false;
  871. }
  872. void obs_property_list_item_disable(obs_property_t *p, size_t idx,
  873. bool disabled)
  874. {
  875. struct list_data *data = get_list_data(p);
  876. if (!data || idx >= data->items.num)
  877. return;
  878. data->items.array[idx].disabled = disabled;
  879. }
  880. const char *obs_property_list_item_name(obs_property_t *p, size_t idx)
  881. {
  882. struct list_data *data = get_list_data(p);
  883. return (data && idx < data->items.num) ?
  884. data->items.array[idx].name : NULL;
  885. }
  886. const char *obs_property_list_item_string(obs_property_t *p, size_t idx)
  887. {
  888. struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_STRING);
  889. return (data && idx < data->items.num) ?
  890. data->items.array[idx].str : NULL;
  891. }
  892. long long obs_property_list_item_int(obs_property_t *p, size_t idx)
  893. {
  894. struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_INT);
  895. return (data && idx < data->items.num) ?
  896. data->items.array[idx].ll : 0;
  897. }
  898. double obs_property_list_item_float(obs_property_t *p, size_t idx)
  899. {
  900. struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_FLOAT);
  901. return (data && idx < data->items.num) ?
  902. data->items.array[idx].d : 0.0;
  903. }
  904. enum obs_editable_list_type obs_property_editable_list_type(obs_property_t *p)
  905. {
  906. struct editable_list_data *data = get_type_data(p,
  907. OBS_PROPERTY_EDITABLE_LIST);
  908. return data ? data->type : OBS_EDITABLE_LIST_TYPE_STRINGS;
  909. }
  910. const char *obs_property_editable_list_filter(obs_property_t *p)
  911. {
  912. struct editable_list_data *data = get_type_data(p,
  913. OBS_PROPERTY_EDITABLE_LIST);
  914. return data ? data->filter : NULL;
  915. }
  916. const char *obs_property_editable_list_default_path(obs_property_t *p)
  917. {
  918. struct editable_list_data *data = get_type_data(p,
  919. OBS_PROPERTY_EDITABLE_LIST);
  920. return data ? data->default_path : NULL;
  921. }
  922. /* ------------------------------------------------------------------------- */
  923. /* OBS_PROPERTY_FRAME_RATE */
  924. void obs_property_frame_rate_clear(obs_property_t *p)
  925. {
  926. struct frame_rate_data *data =
  927. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  928. if (!data) return;
  929. frame_rate_data_options_free(data);
  930. frame_rate_data_ranges_free(data);
  931. }
  932. void obs_property_frame_rate_options_clear(obs_property_t *p)
  933. {
  934. struct frame_rate_data *data =
  935. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  936. if (!data) return;
  937. frame_rate_data_options_free(data);
  938. }
  939. void obs_property_frame_rate_fps_ranges_clear(obs_property_t *p)
  940. {
  941. struct frame_rate_data *data =
  942. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  943. if (!data) return;
  944. frame_rate_data_ranges_free(data);
  945. }
  946. size_t obs_property_frame_rate_option_add(obs_property_t *p,
  947. const char *name, const char *description)
  948. {
  949. struct frame_rate_data *data =
  950. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  951. if (!data) return DARRAY_INVALID;
  952. struct frame_rate_option *opt = da_push_back_new(data->extra_options);
  953. opt->name = bstrdup(name);
  954. opt->description = bstrdup(description);
  955. return data->extra_options.num - 1;
  956. }
  957. size_t obs_property_frame_rate_fps_range_add(obs_property_t *p,
  958. struct media_frames_per_second min,
  959. struct media_frames_per_second max)
  960. {
  961. struct frame_rate_data *data =
  962. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  963. if (!data) return DARRAY_INVALID;
  964. struct frame_rate_range *rng = da_push_back_new(data->ranges);
  965. rng->min_time = min;
  966. rng->max_time = max;
  967. return data->ranges.num - 1;
  968. }
  969. void obs_property_frame_rate_option_insert(obs_property_t *p, size_t idx,
  970. const char *name, const char *description)
  971. {
  972. struct frame_rate_data *data =
  973. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  974. if (!data) return;
  975. struct frame_rate_option *opt = da_insert_new(data->extra_options, idx);
  976. opt->name = bstrdup(name);
  977. opt->description = bstrdup(description);
  978. }
  979. void obs_property_frame_rate_fps_range_insert(obs_property_t *p, size_t idx,
  980. struct media_frames_per_second min,
  981. struct media_frames_per_second max)
  982. {
  983. struct frame_rate_data *data =
  984. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  985. if (!data) return;
  986. struct frame_rate_range *rng = da_insert_new(data->ranges, idx);
  987. rng->min_time = min;
  988. rng->max_time = max;
  989. }
  990. size_t obs_property_frame_rate_options_count(obs_property_t *p)
  991. {
  992. struct frame_rate_data *data =
  993. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  994. return data ? data->extra_options.num : 0;
  995. }
  996. const char *obs_property_frame_rate_option_name(obs_property_t *p,
  997. size_t idx)
  998. {
  999. struct frame_rate_data *data =
  1000. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  1001. return data && data->extra_options.num > idx ?
  1002. data->extra_options.array[idx].name : NULL;
  1003. }
  1004. const char *obs_property_frame_rate_option_description(
  1005. obs_property_t *p, size_t idx)
  1006. {
  1007. struct frame_rate_data *data =
  1008. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  1009. return data && data->extra_options.num > idx ?
  1010. data->extra_options.array[idx].description : NULL;
  1011. }
  1012. size_t obs_property_frame_rate_fps_ranges_count(obs_property_t *p)
  1013. {
  1014. struct frame_rate_data *data =
  1015. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  1016. return data ? data->ranges.num : 0;
  1017. }
  1018. struct media_frames_per_second obs_property_frame_rate_fps_range_min(
  1019. obs_property_t *p, size_t idx)
  1020. {
  1021. struct frame_rate_data *data =
  1022. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  1023. return data && data->ranges.num > idx ?
  1024. data->ranges.array[idx].min_time :
  1025. (struct media_frames_per_second){0};
  1026. }
  1027. struct media_frames_per_second obs_property_frame_rate_fps_range_max(
  1028. obs_property_t *p, size_t idx)
  1029. {
  1030. struct frame_rate_data *data =
  1031. get_type_data(p, OBS_PROPERTY_FRAME_RATE);
  1032. return data && data->ranges.num > idx ?
  1033. data->ranges.array[idx].max_time :
  1034. (struct media_frames_per_second){0};
  1035. }
  1036. enum obs_text_type obs_proprety_text_type(obs_property_t *p)
  1037. {
  1038. return obs_property_text_type(p);
  1039. }
  1040. enum obs_group_type obs_property_group_type(obs_property_t *p)
  1041. {
  1042. struct group_data *data = get_type_data(p, OBS_PROPERTY_GROUP);
  1043. return data ? data->type : OBS_COMBO_INVALID;
  1044. }
  1045. obs_properties_t *obs_property_group_content(obs_property_t *p)
  1046. {
  1047. struct group_data *data = get_type_data(p, OBS_PROPERTY_GROUP);
  1048. return data ? data->content : NULL;
  1049. }