obs-properties.c 33 KB

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