obs-properties.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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. };
  23. struct int_data {
  24. int min, max, step;
  25. };
  26. struct list_item {
  27. char *name;
  28. union {
  29. char *str;
  30. long long ll;
  31. double d;
  32. };
  33. };
  34. struct text_data {
  35. enum obs_text_type type;
  36. };
  37. struct list_data {
  38. DARRAY(struct list_item) items;
  39. enum obs_combo_type type;
  40. enum obs_combo_format format;
  41. };
  42. struct button_data {
  43. obs_property_clicked_t callback;
  44. };
  45. static inline void list_item_free(struct list_data *data,
  46. struct list_item *item)
  47. {
  48. bfree(item->name);
  49. if (data->format == OBS_COMBO_FORMAT_STRING)
  50. bfree(item->str);
  51. }
  52. static inline void list_data_free(struct list_data *data)
  53. {
  54. for (size_t i = 0; i < data->items.num; i++)
  55. list_item_free(data, data->items.array+i);
  56. da_free(data->items);
  57. }
  58. struct obs_properties;
  59. struct obs_property {
  60. const char *name;
  61. const char *desc;
  62. enum obs_property_type type;
  63. bool visible;
  64. bool enabled;
  65. struct obs_properties *parent;
  66. obs_property_modified_t modified;
  67. struct obs_property *next;
  68. };
  69. struct obs_properties {
  70. const char *locale;
  71. void *param;
  72. void (*destroy)(void *param);
  73. struct obs_property *first_property;
  74. struct obs_property **last;
  75. };
  76. obs_properties_t obs_properties_create(const char *locale)
  77. {
  78. struct obs_properties *props;
  79. props = bzalloc(sizeof(struct obs_properties));
  80. props->locale = locale;
  81. props->last = &props->first_property;
  82. return props;
  83. }
  84. void obs_properties_set_param(obs_properties_t props,
  85. void *param, void (*destroy)(void *param))
  86. {
  87. if (!props)
  88. return;
  89. if (props->param && props->destroy)
  90. props->destroy(props->param);
  91. props->param = param;
  92. props->destroy = destroy;
  93. }
  94. void *obs_properties_get_param(obs_properties_t props)
  95. {
  96. return props ? props->param : NULL;
  97. }
  98. obs_properties_t obs_properties_create_param(const char *locale,
  99. void *param, void (*destroy)(void *param))
  100. {
  101. struct obs_properties *props = obs_properties_create(locale);
  102. obs_properties_set_param(props, param, destroy);
  103. return props;
  104. }
  105. static void obs_property_destroy(struct obs_property *property)
  106. {
  107. if (property->type == OBS_PROPERTY_LIST) {
  108. struct list_data *data = get_property_data(property);
  109. list_data_free(data);
  110. }
  111. bfree(property);
  112. }
  113. void obs_properties_destroy(obs_properties_t props)
  114. {
  115. if (props) {
  116. struct obs_property *p = props->first_property;
  117. if (props->destroy && props->param)
  118. props->destroy(props->param);
  119. while (p) {
  120. struct obs_property *next = p->next;
  121. obs_property_destroy(p);
  122. p = next;
  123. }
  124. bfree(props);
  125. }
  126. }
  127. const char *obs_properties_locale(obs_properties_t props)
  128. {
  129. return props ? props->locale : NULL;
  130. }
  131. obs_property_t obs_properties_first(obs_properties_t props)
  132. {
  133. return (props != NULL) ? props->first_property : NULL;
  134. }
  135. obs_property_t obs_properties_get(obs_properties_t props, const char *name)
  136. {
  137. struct obs_property *property;
  138. if (!props)
  139. return NULL;
  140. property = props->first_property;
  141. while (property) {
  142. if (strcmp(property->name, name) == 0)
  143. return property;
  144. property = property->next;
  145. }
  146. return NULL;
  147. }
  148. void obs_properties_apply_settings(obs_properties_t props, obs_data_t settings)
  149. {
  150. struct obs_property *p = props->first_property;
  151. while (p) {
  152. if (p->modified)
  153. p->modified(props, p, settings);
  154. p = p->next;
  155. }
  156. }
  157. /* ------------------------------------------------------------------------- */
  158. static inline void propertes_add(struct obs_properties *props,
  159. struct obs_property *p)
  160. {
  161. *props->last = p;
  162. props->last = &p->next;
  163. }
  164. static inline size_t get_property_size(enum obs_property_type type)
  165. {
  166. switch (type) {
  167. case OBS_PROPERTY_INVALID: return 0;
  168. case OBS_PROPERTY_BOOL: return 0;
  169. case OBS_PROPERTY_INT: return sizeof(struct int_data);
  170. case OBS_PROPERTY_FLOAT: return sizeof(struct float_data);
  171. case OBS_PROPERTY_TEXT: return sizeof(struct text_data);
  172. case OBS_PROPERTY_PATH: return 0;
  173. case OBS_PROPERTY_LIST: return sizeof(struct list_data);
  174. case OBS_PROPERTY_COLOR: return 0;
  175. case OBS_PROPERTY_BUTTON: return sizeof(struct button_data);
  176. }
  177. return 0;
  178. }
  179. static inline struct obs_property *new_prop(struct obs_properties *props,
  180. const char *name, const char *desc,
  181. enum obs_property_type type)
  182. {
  183. size_t data_size = get_property_size(type);
  184. struct obs_property *p;
  185. p = bzalloc(sizeof(struct obs_property) + data_size);
  186. p->parent = props;
  187. p->enabled = true;
  188. p->visible = true;
  189. p->type = type;
  190. p->name = name;
  191. p->desc = desc;
  192. propertes_add(props, p);
  193. return p;
  194. }
  195. static inline bool has_prop(struct obs_properties *props, const char *name)
  196. {
  197. struct obs_property *p = props->first_property;
  198. while (p) {
  199. if (strcmp(p->name, name) == 0) {
  200. blog(LOG_WARNING, "Property '%s' exists", name);
  201. return true;
  202. }
  203. p = p->next;
  204. }
  205. return false;
  206. }
  207. static inline void *get_property_data(struct obs_property *prop)
  208. {
  209. return (uint8_t*)prop + sizeof(struct obs_property);
  210. }
  211. static inline void *get_type_data(struct obs_property *prop,
  212. enum obs_property_type type)
  213. {
  214. if (!prop || prop->type != type)
  215. return NULL;
  216. return get_property_data(prop);
  217. }
  218. obs_property_t obs_properties_add_bool(obs_properties_t props, const char *name,
  219. const char *desc)
  220. {
  221. if (!props || has_prop(props, name)) return NULL;
  222. return new_prop(props, name, desc, OBS_PROPERTY_BOOL);
  223. }
  224. obs_property_t obs_properties_add_int(obs_properties_t props, const char *name,
  225. const char *desc, int min, int max, int step)
  226. {
  227. if (!props || has_prop(props, name)) return NULL;
  228. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_INT);
  229. struct int_data *data = get_property_data(p);
  230. data->min = min;
  231. data->max = max;
  232. data->step = step;
  233. return p;
  234. }
  235. obs_property_t obs_properties_add_float(obs_properties_t props,
  236. const char *name, const char *desc,
  237. double min, double max, double step)
  238. {
  239. if (!props || has_prop(props, name)) return NULL;
  240. struct obs_property *p = new_prop(props, name, desc,
  241. OBS_PROPERTY_FLOAT);
  242. struct float_data *data = get_property_data(p);
  243. data->min = min;
  244. data->max = max;
  245. data->step = step;
  246. return p;
  247. }
  248. obs_property_t obs_properties_add_text(obs_properties_t props, const char *name,
  249. const char *desc, enum obs_text_type type)
  250. {
  251. if (!props || has_prop(props, name)) return NULL;
  252. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_TEXT);
  253. struct text_data *data = get_property_data(p);
  254. data->type = type;
  255. return p;
  256. }
  257. obs_property_t obs_properties_add_path(obs_properties_t props, const char *name,
  258. const char *desc)
  259. {
  260. if (!props || has_prop(props, name)) return NULL;
  261. return new_prop(props, name, desc, OBS_PROPERTY_PATH);
  262. }
  263. obs_property_t obs_properties_add_list(obs_properties_t props,
  264. const char *name, const char *desc,
  265. enum obs_combo_type type,
  266. enum obs_combo_format format)
  267. {
  268. if (!props || has_prop(props, name)) return NULL;
  269. if (type == OBS_COMBO_TYPE_EDITABLE &&
  270. format != OBS_COMBO_FORMAT_STRING) {
  271. blog(LOG_WARNING, "List '%s', error: Editable combo boxes "
  272. "must be of the 'string' type", name);
  273. return NULL;
  274. }
  275. struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_LIST);
  276. struct list_data *data = get_property_data(p);
  277. data->format = format;
  278. data->type = type;
  279. return p;
  280. }
  281. obs_property_t obs_properties_add_color(obs_properties_t props,
  282. const char *name, const char *desc)
  283. {
  284. if (!props || has_prop(props, name)) return NULL;
  285. return new_prop(props, name, desc, OBS_PROPERTY_COLOR);
  286. }
  287. obs_property_t obs_properties_add_button(obs_properties_t props,
  288. const char *name, const char *text,
  289. obs_property_clicked_t callback)
  290. {
  291. if (!props || has_prop(props, name)) return NULL;
  292. struct obs_property *p = new_prop(props, name, text,
  293. OBS_PROPERTY_BUTTON);
  294. struct button_data *data = get_property_data(p);
  295. data->callback = callback;
  296. return p;
  297. }
  298. static inline bool is_combo(struct obs_property *p)
  299. {
  300. return p->type == OBS_PROPERTY_LIST;
  301. }
  302. static inline struct list_data *get_list_data(struct obs_property *p)
  303. {
  304. if (!p || !is_combo(p))
  305. return NULL;
  306. return get_property_data(p);
  307. }
  308. static inline struct list_data *get_list_fmt_data(struct obs_property *p,
  309. enum obs_combo_format format)
  310. {
  311. struct list_data *data = get_list_data(p);
  312. return (data->format == format) ? data : NULL;
  313. }
  314. /* ------------------------------------------------------------------------- */
  315. bool obs_property_next(obs_property_t *p)
  316. {
  317. if (!p || !*p)
  318. return false;
  319. *p = (*p)->next;
  320. return *p != NULL;
  321. }
  322. void obs_property_set_modified_callback(obs_property_t p,
  323. obs_property_modified_t modified)
  324. {
  325. if (p) p->modified = modified;
  326. }
  327. bool obs_property_modified(obs_property_t p, obs_data_t settings)
  328. {
  329. if (p && p->modified)
  330. return p->modified(p->parent, p, settings);
  331. return false;
  332. }
  333. bool obs_property_button_clicked(obs_property_t p, void *obj)
  334. {
  335. struct obs_context_data *context = obj;
  336. if (p) {
  337. struct button_data *data = get_type_data(p,
  338. OBS_PROPERTY_BUTTON);
  339. if (data && data->callback)
  340. return data->callback(p->parent, p, context->data);
  341. }
  342. return false;
  343. }
  344. void obs_property_set_visible(obs_property_t p, bool visible)
  345. {
  346. if (p) p->visible = visible;
  347. }
  348. void obs_property_set_enabled(obs_property_t p, bool enabled)
  349. {
  350. if (p) p->enabled = enabled;
  351. }
  352. const char *obs_property_name(obs_property_t p)
  353. {
  354. return p ? p->name : NULL;
  355. }
  356. const char *obs_property_description(obs_property_t p)
  357. {
  358. return p ? p->desc : NULL;
  359. }
  360. enum obs_property_type obs_property_get_type(obs_property_t p)
  361. {
  362. return p ? p->type : OBS_PROPERTY_INVALID;
  363. }
  364. bool obs_property_enabled(obs_property_t p)
  365. {
  366. return p ? p->enabled : false;
  367. }
  368. bool obs_property_visible(obs_property_t p)
  369. {
  370. return p ? p->visible : false;
  371. }
  372. int obs_property_int_min(obs_property_t p)
  373. {
  374. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  375. return data ? data->min : 0;
  376. }
  377. int obs_property_int_max(obs_property_t p)
  378. {
  379. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  380. return data ? data->max : 0;
  381. }
  382. int obs_property_int_step(obs_property_t p)
  383. {
  384. struct int_data *data = get_type_data(p, OBS_PROPERTY_INT);
  385. return data ? data->step : 0;
  386. }
  387. double obs_property_float_min(obs_property_t p)
  388. {
  389. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  390. return data ? data->min : 0;
  391. }
  392. double obs_property_float_max(obs_property_t p)
  393. {
  394. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  395. return data ? data->max : 0;
  396. }
  397. double obs_property_float_step(obs_property_t p)
  398. {
  399. struct float_data *data = get_type_data(p, OBS_PROPERTY_FLOAT);
  400. return data ? data->step : 0;
  401. }
  402. enum obs_text_type obs_proprety_text_type(obs_property_t p)
  403. {
  404. struct text_data *data = get_type_data(p, OBS_PROPERTY_TEXT);
  405. return data ? data->type : OBS_TEXT_DEFAULT;
  406. }
  407. enum obs_combo_type obs_property_list_type(obs_property_t p)
  408. {
  409. struct list_data *data = get_list_data(p);
  410. return data ? data->type : OBS_COMBO_TYPE_INVALID;
  411. }
  412. enum obs_combo_format obs_property_list_format(obs_property_t p)
  413. {
  414. struct list_data *data = get_list_data(p);
  415. return data ? data->format : OBS_COMBO_FORMAT_INVALID;
  416. }
  417. void obs_property_list_clear(obs_property_t p)
  418. {
  419. struct list_data *data = get_list_data(p);
  420. if (data)
  421. list_data_free(data);
  422. }
  423. static size_t add_item(struct list_data *data, const char *name,
  424. const void *val)
  425. {
  426. struct list_item item;
  427. item.name = bstrdup(name);
  428. if (data->format == OBS_COMBO_FORMAT_INT)
  429. item.ll = *(const long long*)val;
  430. else if (data->format == OBS_COMBO_FORMAT_FLOAT)
  431. item.d = *(const double*)val;
  432. else
  433. item.str = bstrdup(val);
  434. return da_push_back(data->items, &item);
  435. }
  436. size_t obs_property_list_add_string(obs_property_t p,
  437. const char *name, const char *val)
  438. {
  439. struct list_data *data = get_list_data(p);
  440. if (data && data->format == OBS_COMBO_FORMAT_STRING)
  441. return add_item(data, name, val);
  442. return 0;
  443. }
  444. size_t obs_property_list_add_int(obs_property_t p,
  445. const char *name, long long val)
  446. {
  447. struct list_data *data = get_list_data(p);
  448. if (data && data->format == OBS_COMBO_FORMAT_INT)
  449. return add_item(data, name, &val);
  450. return 0;
  451. }
  452. size_t obs_property_list_add_float(obs_property_t p,
  453. const char *name, double val)
  454. {
  455. struct list_data *data = get_list_data(p);
  456. if (data && data->format == OBS_COMBO_FORMAT_FLOAT)
  457. return add_item(data, name, &val);
  458. return 0;
  459. }
  460. void obs_property_list_item_remove(obs_property_t p, size_t idx)
  461. {
  462. struct list_data *data = get_list_data(p);
  463. if (data && idx < data->items.num) {
  464. list_item_free(data, data->items.array+idx);
  465. da_erase(data->items, idx);
  466. }
  467. }
  468. size_t obs_property_list_item_count(obs_property_t p)
  469. {
  470. struct list_data *data = get_list_data(p);
  471. return data ? data->items.num : 0;
  472. }
  473. const char *obs_property_list_item_name(obs_property_t p, size_t idx)
  474. {
  475. struct list_data *data = get_list_data(p);
  476. return (data && idx < data->items.num) ?
  477. data->items.array[idx].name : NULL;
  478. }
  479. const char *obs_property_list_item_string(obs_property_t p, size_t idx)
  480. {
  481. struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_STRING);
  482. return (data && idx < data->items.num) ?
  483. data->items.array[idx].str : "";
  484. }
  485. long long obs_property_list_item_int(obs_property_t p, size_t idx)
  486. {
  487. struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_INT);
  488. return (data && idx < data->items.num) ?
  489. data->items.array[idx].ll : 0;
  490. }
  491. double obs_property_list_item_float(obs_property_t p, size_t idx)
  492. {
  493. struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_FLOAT);
  494. return (data && idx < data->items.num) ?
  495. data->items.array[idx].d : 0.0;
  496. }