PageRenderTime 72ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/blender-2.63a/source/blender/editors/interface/interface_templates.c

#
C | 2744 lines | 1943 code | 531 blank | 270 comment | 525 complexity | 618cad00d3cbe6ae7d73caa7a245fe66 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, BSD-3-Clause, LGPL-3.0, BSD-2-Clause, Apache-2.0, AGPL-1.0
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * Contributor(s): Blender Foundation 2009.
  19. *
  20. * ***** END GPL LICENSE BLOCK *****
  21. */
  22. /** \file blender/editors/interface/interface_templates.c
  23. * \ingroup edinterface
  24. */
  25. #include <stdlib.h>
  26. #include <stddef.h>
  27. #include <string.h>
  28. #include "MEM_guardedalloc.h"
  29. #include "DNA_anim_types.h"
  30. #include "DNA_dynamicpaint_types.h"
  31. #include "DNA_key_types.h"
  32. #include "DNA_scene_types.h"
  33. #include "DNA_userdef_types.h"
  34. #include "BLI_utildefines.h"
  35. #include "BLI_string.h"
  36. #include "BLI_ghash.h"
  37. #include "BLF_translation.h"
  38. #include "BKE_animsys.h"
  39. #include "BKE_colortools.h"
  40. #include "BKE_context.h"
  41. #include "BKE_dynamicpaint.h"
  42. #include "BKE_global.h"
  43. #include "BKE_library.h"
  44. #include "BKE_main.h"
  45. #include "BKE_object.h"
  46. #include "BKE_material.h"
  47. #include "BKE_texture.h"
  48. #include "BKE_report.h"
  49. #include "BKE_displist.h"
  50. #include "BKE_scene.h"
  51. #include "ED_screen.h"
  52. #include "ED_object.h"
  53. #include "ED_render.h"
  54. #include "RNA_access.h"
  55. #include "RNA_enum_types.h"
  56. #include "WM_api.h"
  57. #include "WM_types.h"
  58. #include "UI_interface.h"
  59. #include "interface_intern.h"
  60. #include "BLF_api.h"
  61. #include "BLF_translation.h"
  62. void UI_template_fix_linking(void)
  63. {
  64. }
  65. /********************** Header Template *************************/
  66. void uiTemplateHeader(uiLayout *layout, bContext *C, int menus)
  67. {
  68. uiBlock *block;
  69. block = uiLayoutAbsoluteBlock(layout);
  70. if (menus) ED_area_header_standardbuttons(C, block, 0);
  71. else ED_area_header_switchbutton(C, block, 0);
  72. }
  73. /********************** Search Callbacks *************************/
  74. typedef struct TemplateID {
  75. PointerRNA ptr;
  76. PropertyRNA *prop;
  77. ListBase *idlb;
  78. int prv_rows, prv_cols;
  79. int preview;
  80. } TemplateID;
  81. /* Search browse menu, assign */
  82. static void id_search_call_cb(bContext *C, void *arg_template, void *item)
  83. {
  84. TemplateID *template = (TemplateID *)arg_template;
  85. /* ID */
  86. if (item) {
  87. PointerRNA idptr;
  88. RNA_id_pointer_create(item, &idptr);
  89. RNA_property_pointer_set(&template->ptr, template->prop, idptr);
  90. RNA_property_update(C, &template->ptr, template->prop);
  91. }
  92. }
  93. /* ID Search browse menu, do the search */
  94. static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
  95. {
  96. TemplateID *template = (TemplateID *)arg_template;
  97. ListBase *lb = template->idlb;
  98. ID *id, *id_from = template->ptr.id.data;
  99. int iconid;
  100. int flag = RNA_property_flag(template->prop);
  101. /* ID listbase */
  102. for (id = lb->first; id; id = id->next) {
  103. if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
  104. /* use filter */
  105. if (RNA_property_type(template->prop) == PROP_POINTER) {
  106. PointerRNA ptr;
  107. RNA_id_pointer_create(id, &ptr);
  108. if (RNA_property_pointer_poll(&template->ptr, template->prop, &ptr) == 0)
  109. continue;
  110. }
  111. /* hide dot-datablocks, but only if filter does not force it visible */
  112. if (U.uiflag & USER_HIDE_DOT)
  113. if ((id->name[2] == '.') && (str[0] != '.'))
  114. continue;
  115. if (BLI_strcasestr(id->name + 2, str)) {
  116. char name_ui[MAX_ID_NAME];
  117. name_uiprefix_id(name_ui, id);
  118. iconid = ui_id_icon_get((bContext *)C, id, template->preview);
  119. if (!uiSearchItemAdd(items, name_ui, id, iconid))
  120. break;
  121. }
  122. }
  123. }
  124. }
  125. /* ID Search browse menu, open */
  126. static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
  127. {
  128. static char search[256];
  129. static TemplateID template;
  130. PointerRNA idptr;
  131. wmWindow *win = CTX_wm_window(C);
  132. uiBlock *block;
  133. uiBut *but;
  134. /* clear initial search string, then all items show */
  135. search[0] = 0;
  136. /* arg_litem is malloced, can be freed by parent button */
  137. template = *((TemplateID *)arg_litem);
  138. /* get active id for showing first item */
  139. idptr = RNA_property_pointer_get(&template.ptr, template.prop);
  140. block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
  141. uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_RET_1);
  142. /* preview thumbnails */
  143. if (template.prv_rows > 0 && template.prv_cols > 0) {
  144. int w = 96 * template.prv_cols;
  145. int h = 96 * template.prv_rows + 20;
  146. /* fake button, it holds space for search items */
  147. uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
  148. but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
  149. uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
  150. }
  151. /* list view */
  152. else {
  153. /* fake button, it holds space for search items */
  154. uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
  155. but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, 19, 0, 0, "");
  156. uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
  157. }
  158. uiBoundsBlock(block, 6);
  159. uiBlockSetDirection(block, UI_DOWN);
  160. uiEndBlock(C, block);
  161. /* give search-field focus */
  162. uiButSetFocusOnEnter(win, but);
  163. /* this type of search menu requires undo */
  164. but->flag |= UI_BUT_UNDO;
  165. return block;
  166. }
  167. /************************ ID Template ***************************/
  168. /* This is for browsing and editing the ID-blocks used */
  169. /* for new/open operators */
  170. void uiIDContextProperty(bContext *C, PointerRNA *ptr, PropertyRNA **prop)
  171. {
  172. TemplateID *template;
  173. ARegion *ar = CTX_wm_region(C);
  174. uiBlock *block;
  175. uiBut *but;
  176. memset(ptr, 0, sizeof(*ptr));
  177. *prop = NULL;
  178. if (!ar)
  179. return;
  180. for (block = ar->uiblocks.first; block; block = block->next) {
  181. for (but = block->buttons.first; but; but = but->next) {
  182. /* find the button before the active one */
  183. if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
  184. if (but->func_argN) {
  185. template = but->func_argN;
  186. *ptr = template->ptr;
  187. *prop = template->prop;
  188. return;
  189. }
  190. }
  191. }
  192. }
  193. }
  194. static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
  195. {
  196. TemplateID *template = (TemplateID *)arg_litem;
  197. PointerRNA idptr = RNA_property_pointer_get(&template->ptr, template->prop);
  198. ID *id = idptr.data;
  199. int event = GET_INT_FROM_POINTER(arg_event);
  200. switch (event) {
  201. case UI_ID_BROWSE:
  202. case UI_ID_PIN:
  203. RNA_warning("warning, id event %d shouldnt come here", event);
  204. break;
  205. case UI_ID_OPEN:
  206. case UI_ID_ADD_NEW:
  207. /* these call uiIDContextPropertySet */
  208. break;
  209. case UI_ID_DELETE:
  210. memset(&idptr, 0, sizeof(idptr));
  211. RNA_property_pointer_set(&template->ptr, template->prop, idptr);
  212. RNA_property_update(C, &template->ptr, template->prop);
  213. if (id && CTX_wm_window(C)->eventstate->shift) /* useful hidden functionality, */
  214. id->us = 0;
  215. break;
  216. case UI_ID_FAKE_USER:
  217. if (id) {
  218. if (id->flag & LIB_FAKEUSER) id_us_plus(id);
  219. else id_us_min(id);
  220. }
  221. else return;
  222. break;
  223. case UI_ID_LOCAL:
  224. if (id) {
  225. if (id_make_local(id, 0)) {
  226. /* reassign to get get proper updates/notifiers */
  227. idptr = RNA_property_pointer_get(&template->ptr, template->prop);
  228. RNA_property_pointer_set(&template->ptr, template->prop, idptr);
  229. RNA_property_update(C, &template->ptr, template->prop);
  230. }
  231. }
  232. break;
  233. case UI_ID_ALONE:
  234. if (id) {
  235. const int do_scene_obj = (GS(id->name) == ID_OB) &&
  236. (template->ptr.type == &RNA_SceneObjects);
  237. /* make copy */
  238. if (do_scene_obj) {
  239. Scene *scene = CTX_data_scene(C);
  240. ED_object_single_user(scene, (struct Object *)id);
  241. WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
  242. }
  243. else {
  244. if (id) {
  245. id_single_user(C, id, &template->ptr, template->prop);
  246. }
  247. }
  248. }
  249. break;
  250. #if 0
  251. case UI_ID_AUTO_NAME:
  252. break;
  253. #endif
  254. }
  255. }
  256. static const char *template_id_browse_tip(StructRNA *type)
  257. {
  258. if (type) {
  259. switch (RNA_type_to_ID_code(type)) {
  260. case ID_SCE: return N_("Browse Scene to be linked");
  261. case ID_OB: return N_("Browse Object to be linked");
  262. case ID_ME: return N_("Browse Mesh Data to be linked");
  263. case ID_CU: return N_("Browse Curve Data to be linked");
  264. case ID_MB: return N_("Browse Metaball Data to be linked");
  265. case ID_MA: return N_("Browse Material to be linked");
  266. case ID_TE: return N_("Browse Texture to be linked");
  267. case ID_IM: return N_("Browse Image to be linked");
  268. case ID_LT: return N_("Browse Lattice Data to be linked");
  269. case ID_LA: return N_("Browse Lamp Data to be linked");
  270. case ID_CA: return N_("Browse Camera Data to be linked");
  271. case ID_WO: return N_("Browse World Settings to be linked");
  272. case ID_SCR: return N_("Choose Screen lay-out");
  273. case ID_TXT: return N_("Browse Text to be linked");
  274. case ID_SPK: return N_("Browse Speaker Data to be linked");
  275. case ID_SO: return N_("Browse Sound to be linked");
  276. case ID_AR: return N_("Browse Armature data to be linked");
  277. case ID_AC: return N_("Browse Action to be linked");
  278. case ID_NT: return N_("Browse Node Tree to be linked");
  279. case ID_BR: return N_("Browse Brush to be linked");
  280. case ID_PA: return N_("Browse Particle System to be linked");
  281. case ID_GD: return N_("Browse Grease Pencil Data to be linked");
  282. }
  283. }
  284. return N_("Browse ID data to be linked");
  285. }
  286. static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag, const char *newop, const char *openop, const char *unlinkop)
  287. {
  288. uiBut *but;
  289. uiBlock *block;
  290. PointerRNA idptr;
  291. // ListBase *lb; // UNUSED
  292. ID *id, *idfrom;
  293. int editable = RNA_property_editable(&template->ptr, template->prop);
  294. idptr = RNA_property_pointer_get(&template->ptr, template->prop);
  295. id = idptr.data;
  296. idfrom = template->ptr.id.data;
  297. // lb= template->idlb;
  298. block = uiLayoutGetBlock(layout);
  299. uiBlockBeginAlign(block);
  300. if (idptr.type)
  301. type = idptr.type;
  302. if (flag & UI_ID_PREVIEWS) {
  303. but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6,
  304. TIP_(template_id_browse_tip(type)));
  305. if (type) {
  306. but->icon = RNA_struct_ui_icon(type);
  307. if (id) but->icon = ui_id_icon_get(C, id, 1);
  308. uiButSetFlag(but, UI_HAS_ICON | UI_ICON_PREVIEW);
  309. }
  310. if ((idfrom && idfrom->lib) || !editable)
  311. uiButSetFlag(but, UI_BUT_DISABLED);
  312. uiLayoutRow(layout, 1);
  313. template->preview = 1;
  314. }
  315. else if (flag & UI_ID_BROWSE) {
  316. but = uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y,
  317. TIP_(template_id_browse_tip(type)));
  318. if (type) {
  319. but->icon = RNA_struct_ui_icon(type);
  320. /* default dragging of icon for id browse buttons */
  321. uiButSetDragID(but, id);
  322. uiButSetFlag(but, UI_HAS_ICON | UI_ICON_LEFT);
  323. }
  324. if ((idfrom && idfrom->lib) || !editable)
  325. uiButSetFlag(but, UI_BUT_DISABLED);
  326. }
  327. /* text button with name */
  328. if (id) {
  329. char name[UI_MAX_NAME_STR];
  330. const short user_alert = (id->us <= 0);
  331. //text_idbutton(id, name);
  332. name[0] = '\0';
  333. but = uiDefButR(block, TEX, 0, name, 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, &idptr, "name", -1, 0, 0, -1, -1, NULL);
  334. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
  335. if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
  336. if (id->lib) {
  337. if (id->flag & LIB_INDIRECT) {
  338. but = uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  339. TIP_("Indirect library datablock, cannot change"));
  340. uiButSetFlag(but, UI_BUT_DISABLED);
  341. }
  342. else {
  343. but = uiDefIconBut(block, BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  344. TIP_("Direct linked library datablock, click to make local"));
  345. if (!id_make_local(id, 1 /* test */) || (idfrom && idfrom->lib))
  346. uiButSetFlag(but, UI_BUT_DISABLED);
  347. }
  348. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
  349. }
  350. if (id->us > 1) {
  351. char numstr[32];
  352. BLI_snprintf(numstr, sizeof(numstr), "%d", id->us);
  353. but = uiDefBut(block, BUT, 0, numstr, 0, 0, UI_UNIT_X + ((id->us < 10) ? 0 : 10), UI_UNIT_Y, NULL, 0, 0, 0, 0,
  354. TIP_("Display number of users of this data (click to make a single-user copy)"));
  355. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
  356. if (!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib) || !editable)
  357. uiButSetFlag(but, UI_BUT_DISABLED);
  358. }
  359. if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
  360. if (id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
  361. uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
  362. }
  363. }
  364. if (flag & UI_ID_ADD_NEW) {
  365. int w = id ? UI_UNIT_X : (flag & UI_ID_OPEN) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
  366. if (newop) {
  367. but = uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, (id) ? "" : IFACE_("New"), 0, 0, w, UI_UNIT_Y, NULL);
  368. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
  369. }
  370. else {
  371. but = uiDefIconTextBut(block, BUT, 0, ICON_ZOOMIN, (id) ? "" : IFACE_("New"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
  372. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
  373. }
  374. if ((idfrom && idfrom->lib) || !editable)
  375. uiButSetFlag(but, UI_BUT_DISABLED);
  376. }
  377. if (flag & UI_ID_OPEN) {
  378. int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
  379. if (openop) {
  380. but = uiDefIconTextButO(block, BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y, NULL);
  381. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
  382. }
  383. else {
  384. but = uiDefIconTextBut(block, BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
  385. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
  386. }
  387. if ((idfrom && idfrom->lib) || !editable)
  388. uiButSetFlag(but, UI_BUT_DISABLED);
  389. }
  390. /* delete button */
  391. if (id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
  392. if (unlinkop) {
  393. but = uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
  394. /* so we can access the template from operators, font unlinking needs this */
  395. uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
  396. }
  397. else {
  398. but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  399. TIP_("Unlink datablock. Shift + Click to set users to zero, data will then not be saved"));
  400. uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
  401. if (RNA_property_flag(template->prop) & PROP_NEVER_NULL)
  402. uiButSetFlag(but, UI_BUT_DISABLED);
  403. }
  404. if ((idfrom && idfrom->lib) || !editable)
  405. uiButSetFlag(but, UI_BUT_DISABLED);
  406. }
  407. if (idcode == ID_TE)
  408. uiTemplateTextureShow(layout, C, &template->ptr, template->prop);
  409. uiBlockEndAlign(block);
  410. }
  411. static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols)
  412. {
  413. TemplateID *template;
  414. PropertyRNA *prop;
  415. StructRNA *type;
  416. short idcode;
  417. prop = RNA_struct_find_property(ptr, propname);
  418. if (!prop || RNA_property_type(prop) != PROP_POINTER) {
  419. RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
  420. return;
  421. }
  422. template = MEM_callocN(sizeof(TemplateID), "TemplateID");
  423. template->ptr = *ptr;
  424. template->prop = prop;
  425. template->prv_rows = prv_rows;
  426. template->prv_cols = prv_cols;
  427. if (newop)
  428. flag |= UI_ID_ADD_NEW;
  429. if (openop)
  430. flag |= UI_ID_OPEN;
  431. type = RNA_property_pointer_type(ptr, prop);
  432. idcode = RNA_type_to_ID_code(type);
  433. template->idlb = which_libbase(CTX_data_main(C), idcode);
  434. /* create UI elements for this template
  435. * - template_ID makes a copy of the template data and assigns it to the relevant buttons
  436. */
  437. if (template->idlb) {
  438. uiLayoutRow(layout, 1);
  439. template_ID(C, layout, template, type, idcode, flag, newop, openop, unlinkop);
  440. }
  441. MEM_freeN(template);
  442. }
  443. void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
  444. {
  445. ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, 0, 0);
  446. }
  447. void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop)
  448. {
  449. ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, 0, 0);
  450. }
  451. void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols)
  452. {
  453. ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, rows, cols);
  454. }
  455. /************************ ID Chooser Template ***************************/
  456. /* This is for selecting the type of ID-block to use, and then from the relevant type choosing the block to use
  457. *
  458. * - propname: property identifier for property that ID-pointer gets stored to
  459. * - proptypename: property identifier for property used to determine the type of ID-pointer that can be used
  460. */
  461. void uiTemplateAnyID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename, const char *text)
  462. {
  463. PropertyRNA *propID, *propType;
  464. uiLayout *row;
  465. /* get properties... */
  466. propID = RNA_struct_find_property(ptr, propname);
  467. propType = RNA_struct_find_property(ptr, proptypename);
  468. if (!propID || RNA_property_type(propID) != PROP_POINTER) {
  469. RNA_warning("pointer property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
  470. return;
  471. }
  472. if (!propType || RNA_property_type(propType) != PROP_ENUM) {
  473. RNA_warning("pointer-type property not found: %s.%s", RNA_struct_identifier(ptr->type), proptypename);
  474. return;
  475. }
  476. /* Start drawing UI Elements using standard defines */
  477. row = uiLayoutRow(layout, 1);
  478. /* Label - either use the provided text, or will become "ID-Block:" */
  479. if (text)
  480. uiItemL(row, text, ICON_NONE);
  481. else
  482. uiItemL(row, "ID-Block:", ICON_NONE);
  483. /* ID-Type Selector - just have a menu of icons */
  484. // FIXME: the icon-only setting doesn't work when we supply a blank name
  485. uiItemFullR(row, ptr, propType, 0, 0, UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
  486. /* ID-Block Selector - just use pointer widget... */
  487. uiItemFullR(row, ptr, propID, 0, 0, 0, "", ICON_NONE);
  488. }
  489. /********************* RNA Path Builder Template ********************/
  490. /* ---------- */
  491. /* This is creating/editing RNA-Paths
  492. *
  493. * - ptr: struct which holds the path property
  494. * - propname: property identifier for property that path gets stored to
  495. * - root_ptr: struct that path gets built from
  496. */
  497. void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *UNUSED(root_ptr), const char *text)
  498. {
  499. PropertyRNA *propPath;
  500. uiLayout *row;
  501. /* check that properties are valid */
  502. propPath = RNA_struct_find_property(ptr, propname);
  503. if (!propPath || RNA_property_type(propPath) != PROP_STRING) {
  504. RNA_warning("path property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
  505. return;
  506. }
  507. /* Start drawing UI Elements using standard defines */
  508. row = uiLayoutRow(layout, 1);
  509. /* Path (existing string) Widget */
  510. uiItemR(row, ptr, propname, 0, text, ICON_RNA);
  511. // TODO: attach something to this to make allow searching of nested properties to 'build' the path
  512. }
  513. /************************ Modifier Template *************************/
  514. #define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
  515. #include <string.h>
  516. #include "DNA_object_force.h"
  517. #include "BKE_depsgraph.h"
  518. #include "BKE_modifier.h"
  519. #include "BKE_particle.h"
  520. #include "ED_util.h"
  521. #include "BLI_math.h"
  522. #include "BLI_listbase.h"
  523. #include "ED_object.h"
  524. static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
  525. {
  526. Scene *scene = CTX_data_scene(C);
  527. Object *ob = ob_v;
  528. ModifierData *md = md_v;
  529. int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
  530. /* undo button operation */
  531. md->mode ^= eModifierMode_OnCage;
  532. for (i = 0, md = ob->modifiers.first; md; ++i, md = md->next) {
  533. if (md == md_v) {
  534. if (i >= cageIndex)
  535. md->mode ^= eModifierMode_OnCage;
  536. break;
  537. }
  538. }
  539. WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
  540. DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
  541. }
  542. static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
  543. {
  544. Object *ob = ob_v;
  545. ModifierData *md = md_v;
  546. ModifierData *nmd = modifier_new(md->type);
  547. modifier_copyData(md, nmd);
  548. nmd->mode &= ~eModifierMode_Virtual;
  549. BLI_addhead(&ob->modifiers, nmd);
  550. modifier_unique_name(&ob->modifiers, nmd);
  551. ob->partype = PAROBJECT;
  552. WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
  553. DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
  554. ED_undo_push(C, "Modifier convert to real");
  555. }
  556. static int modifier_can_delete(ModifierData *md)
  557. {
  558. /* fluid particle modifier can't be deleted here */
  559. if (md->type == eModifierType_ParticleSystem)
  560. if (((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID)
  561. return 0;
  562. return 1;
  563. }
  564. /* Check wheter Modifier is a simulation or not, this is used for switching to the physics/particles context tab */
  565. static int modifier_is_simulation(ModifierData *md)
  566. {
  567. /* Physic Tab */
  568. if (ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
  569. eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint))
  570. {
  571. return 1;
  572. }
  573. /* Particle Tab */
  574. else if (md->type == eModifierType_ParticleSystem) {
  575. return 2;
  576. }
  577. else {
  578. return 0;
  579. }
  580. }
  581. static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
  582. ModifierData *md, int index, int cageIndex, int lastCageIndex)
  583. {
  584. ModifierTypeInfo *mti = modifierType_getInfo(md->type);
  585. PointerRNA ptr;
  586. uiBut *but;
  587. uiBlock *block;
  588. uiLayout *box, *column, *row;
  589. uiLayout *result = NULL;
  590. int isVirtual = (md->mode & eModifierMode_Virtual);
  591. char str[128];
  592. /* create RNA pointer */
  593. RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr);
  594. column = uiLayoutColumn(layout, 1);
  595. uiLayoutSetContextPointer(column, "modifier", &ptr);
  596. /* rounded header ------------------------------------------------------------------- */
  597. box = uiLayoutBox(column);
  598. if (isVirtual) {
  599. row = uiLayoutRow(box, 0);
  600. uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_EXPAND);
  601. block = uiLayoutGetBlock(row);
  602. /* VIRTUAL MODIFIER */
  603. // XXX this is not used now, since these cannot be accessed via RNA
  604. BLI_snprintf(str, sizeof(str), "%s parent deform", md->name);
  605. uiDefBut(block, LABEL, 0, str, 0, 0, 185, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name");
  606. but = uiDefBut(block, BUT, 0, IFACE_("Make Real"), 0, 0, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0,
  607. TIP_("Convert virtual modifier to a real modifier"));
  608. uiButSetFunc(but, modifiers_convertToReal, ob, md);
  609. }
  610. else {
  611. /* REAL MODIFIER */
  612. row = uiLayoutRow(box, 0);
  613. block = uiLayoutGetBlock(row);
  614. uiBlockSetEmboss(block, UI_EMBOSSN);
  615. /* Open/Close ................................. */
  616. uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE);
  617. /* modifier-type icon */
  618. uiItemL(row, "", RNA_struct_ui_icon(ptr.type));
  619. uiBlockSetEmboss(block, UI_EMBOSS);
  620. /* modifier name */
  621. uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
  622. /* mode enabling buttons */
  623. uiBlockBeginAlign(block);
  624. /* Softbody not allowed in this situation, enforce! */
  625. if (((md->type != eModifierType_Softbody && md->type != eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) &&
  626. (md->type != eModifierType_Surface) )
  627. {
  628. uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
  629. uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
  630. if (mti->flags & eModifierTypeFlag_SupportsEditmode)
  631. uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE);
  632. }
  633. if (ob->type == OB_MESH) {
  634. if (modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) {
  635. /* -- convert to rna ? */
  636. but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
  637. TIP_("Apply modifier to editing cage during Editmode"));
  638. if (index < cageIndex)
  639. uiButSetFlag(but, UI_BUT_DISABLED);
  640. uiButSetFunc(but, modifiers_setOnCage, ob, md);
  641. }
  642. else {
  643. uiBlockEndAlign(block);
  644. /* place holder button */
  645. uiBlockSetEmboss(block, UI_EMBOSSN);
  646. but = uiDefIconBut(block, BUT, 0, ICON_NONE, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, NULL);
  647. uiButSetFlag(but, UI_BUT_DISABLED);
  648. uiBlockSetEmboss(block, UI_EMBOSS);
  649. }
  650. } /* tessellation point for curve-typed objects */
  651. else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
  652. /* some modifiers could work with pre-tessellated curves only */
  653. if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
  654. /* add disabled pre-tessellated button, so users could have
  655. * message for this modifiers */
  656. but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
  657. TIP_("This modifier could be applied on splines' points only"));
  658. uiButSetFlag(but, UI_BUT_DISABLED);
  659. }
  660. else if (mti->type != eModifierTypeType_Constructive) {
  661. /* constructive modifiers tessellates curve before applying */
  662. uiItemR(row, &ptr, "use_apply_on_spline", 0, "", ICON_NONE);
  663. }
  664. }
  665. uiBlockEndAlign(block);
  666. /* Up/Down + Delete ........................... */
  667. uiBlockBeginAlign(block);
  668. uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_modifier_move_up");
  669. uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_modifier_move_down");
  670. uiBlockEndAlign(block);
  671. uiBlockSetEmboss(block, UI_EMBOSSN);
  672. // When Modifier is a simulation, show button to switch to context rather than the delete button.
  673. if (modifier_can_delete(md) && !modifier_is_simulation(md))
  674. uiItemO(row, "", ICON_X, "OBJECT_OT_modifier_remove");
  675. if (modifier_is_simulation(md) == 1)
  676. uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PHYSICS");
  677. else if (modifier_is_simulation(md) == 2)
  678. uiItemStringO(row, "", ICON_BUTS, "WM_OT_properties_context_change", "context", "PARTICLES");
  679. uiBlockSetEmboss(block, UI_EMBOSS);
  680. }
  681. /* modifier settings (under the header) --------------------------------------------------- */
  682. if (!isVirtual && (md->mode & eModifierMode_Expanded)) {
  683. /* apply/convert/copy */
  684. box = uiLayoutBox(column);
  685. row = uiLayoutRow(box, 0);
  686. if (!ELEM(md->type, eModifierType_Collision, eModifierType_Surface)) {
  687. /* only here obdata, the rest of modifiers is ob level */
  688. uiBlockSetButLock(block, object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
  689. if (md->type == eModifierType_ParticleSystem) {
  690. ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
  691. if (!(ob->mode & OB_MODE_PARTICLE_EDIT) && psys->pathcache) {
  692. if (ELEM(psys->part->ren_as, PART_DRAW_GR, PART_DRAW_OB))
  693. uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_duplicates_make_real");
  694. else if (psys->part->ren_as == PART_DRAW_PATH)
  695. uiItemO(row, "Convert", ICON_NONE, "OBJECT_OT_modifier_convert");
  696. }
  697. }
  698. else {
  699. uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
  700. uiItemEnumO(row, "OBJECT_OT_modifier_apply", IFACE_("Apply"), 0, "apply_as", MODIFIER_APPLY_DATA);
  701. if (modifier_sameTopology(md) && !modifier_nonGeometrical(md))
  702. uiItemEnumO(row, "OBJECT_OT_modifier_apply", IFACE_("Apply as Shape Key"), 0, "apply_as", MODIFIER_APPLY_SHAPE);
  703. }
  704. uiBlockClearButLock(block);
  705. uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
  706. if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke))
  707. uiItemO(row, IFACE_("Copy"), ICON_NONE, "OBJECT_OT_modifier_copy");
  708. }
  709. /* result is the layout block inside the box, that we return so that modifier settings can be drawn */
  710. result = uiLayoutColumn(box, 0);
  711. block = uiLayoutAbsoluteBlock(box);
  712. }
  713. /* error messages */
  714. if (md->error) {
  715. box = uiLayoutBox(column);
  716. row = uiLayoutRow(box, 0);
  717. uiItemL(row, md->error, ICON_ERROR);
  718. }
  719. return result;
  720. }
  721. uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
  722. {
  723. Scene *scene = CTX_data_scene(C);
  724. Object *ob;
  725. ModifierData *md, *vmd;
  726. int i, lastCageIndex, cageIndex;
  727. /* verify we have valid data */
  728. if (!RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
  729. RNA_warning("Expected modifier on object");
  730. return NULL;
  731. }
  732. ob = ptr->id.data;
  733. md = ptr->data;
  734. if (!ob || !(GS(ob->id.name) == ID_OB)) {
  735. RNA_warning("Expected modifier on object");
  736. return NULL;
  737. }
  738. uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
  739. /* find modifier and draw it */
  740. cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
  741. // XXX virtual modifiers are not accesible for python
  742. vmd = modifiers_getVirtualModifierList(ob);
  743. for (i = 0; vmd; i++, vmd = vmd->next) {
  744. if (md == vmd)
  745. return draw_modifier(layout, scene, ob, md, i, cageIndex, lastCageIndex);
  746. else if (vmd->mode & eModifierMode_Virtual)
  747. i--;
  748. }
  749. return NULL;
  750. }
  751. /************************ Constraint Template *************************/
  752. #include "DNA_constraint_types.h"
  753. #include "BKE_action.h"
  754. #include "BKE_constraint.h"
  755. #define REDRAWIPO 1
  756. #define REDRAWNLA 2
  757. #define REDRAWBUTSOBJECT 3
  758. #define REDRAWACTION 4
  759. #define B_CONSTRAINT_TEST 5
  760. #define B_CONSTRAINT_CHANGETARGET 6
  761. #define REMAKEIPO 8
  762. #define B_DIFF 9
  763. static void do_constraint_panels(bContext *C, void *ob_pt, int event)
  764. {
  765. Main *bmain = CTX_data_main(C);
  766. Scene *scene = CTX_data_scene(C);
  767. Object *ob = (Object *)ob_pt;
  768. switch (event) {
  769. case B_CONSTRAINT_TEST:
  770. break; // no handling
  771. case B_CONSTRAINT_CHANGETARGET:
  772. if (ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels
  773. DAG_scene_sort(bmain, scene);
  774. break;
  775. default:
  776. break;
  777. }
  778. // note: RNA updates now call this, commenting else it gets called twice.
  779. // if there are problems because of this, then rna needs changed update functions.
  780. //
  781. // object_test_constraints(ob);
  782. // if (ob->pose) update_pose_constraint_flags(ob->pose);
  783. if (ob->type == OB_ARMATURE) DAG_id_tag_update(&ob->id, OB_RECALC_DATA | OB_RECALC_OB);
  784. else DAG_id_tag_update(&ob->id, OB_RECALC_OB);
  785. WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
  786. }
  787. static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
  788. {
  789. ED_object_constraint_set_active(ob_v, con_v);
  790. }
  791. /* draw panel showing settings for a constraint */
  792. static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
  793. {
  794. bPoseChannel *pchan = get_active_posechannel(ob);
  795. bConstraintTypeInfo *cti;
  796. uiBlock *block;
  797. uiLayout *result = NULL, *col, *box, *row;
  798. PointerRNA ptr;
  799. char typestr[32];
  800. short proxy_protected, xco = 0, yco = 0;
  801. // int rb_col; // UNUSED
  802. /* get constraint typeinfo */
  803. cti = constraint_get_typeinfo(con);
  804. if (cti == NULL) {
  805. /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
  806. BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr));
  807. }
  808. else
  809. BLI_strncpy(typestr, cti->name, sizeof(typestr));
  810. /* determine whether constraint is proxy protected or not */
  811. if (proxylocked_constraints_owner(ob, pchan))
  812. proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0;
  813. else
  814. proxy_protected = 0;
  815. /* unless button has own callback, it adds this callback to button */
  816. block = uiLayoutGetBlock(layout);
  817. uiBlockSetHandleFunc(block, do_constraint_panels, ob);
  818. uiBlockSetFunc(block, constraint_active_func, ob, con);
  819. RNA_pointer_create(&ob->id, &RNA_Constraint, con, &ptr);
  820. col = uiLayoutColumn(layout, 1);
  821. uiLayoutSetContextPointer(col, "constraint", &ptr);
  822. box = uiLayoutBox(col);
  823. row = uiLayoutRow(box, 0);
  824. block = uiLayoutGetBlock(box);
  825. /* Draw constraint header */
  826. /* open/close */
  827. uiBlockSetEmboss(block, UI_EMBOSSN);
  828. uiItemR(row, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
  829. uiBlockSetEmboss(block, UI_EMBOSS);
  830. /* name */
  831. uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, xco + 10, yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
  832. if (con->flag & CONSTRAINT_DISABLE)
  833. uiLayoutSetRedAlert(row, 1);
  834. if (proxy_protected == 0) {
  835. uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
  836. }
  837. else
  838. uiItemL(row, con->name, ICON_NONE);
  839. uiLayoutSetRedAlert(row, 0);
  840. /* proxy-protected constraints cannot be edited, so hide up/down + close buttons */
  841. if (proxy_protected) {
  842. uiBlockSetEmboss(block, UI_EMBOSSN);
  843. /* draw a ghost icon (for proxy) and also a lock beside it, to show that constraint is "proxy locked" */
  844. uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_GHOST, xco + 244, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Proxy Protected"));
  845. uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, ICON_LOCKED, xco + 262, yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Proxy Protected"));
  846. uiBlockSetEmboss(block, UI_EMBOSS);
  847. }
  848. else {
  849. short prev_proxylock, show_upbut, show_downbut;
  850. /* Up/Down buttons:
  851. * Proxy-constraints are not allowed to occur after local (non-proxy) constraints
  852. * as that poses problems when restoring them, so disable the "up" button where
  853. * it may cause this situation.
  854. *
  855. * Up/Down buttons should only be shown (or not greyed - todo) if they serve some purpose.
  856. */
  857. if (proxylocked_constraints_owner(ob, pchan)) {
  858. if (con->prev) {
  859. prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
  860. }
  861. else
  862. prev_proxylock = 0;
  863. }
  864. else
  865. prev_proxylock = 0;
  866. show_upbut = ((prev_proxylock == 0) && (con->prev));
  867. show_downbut = (con->next) ? 1 : 0;
  868. /* enabled */
  869. uiBlockSetEmboss(block, UI_EMBOSSN);
  870. uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF);
  871. uiBlockSetEmboss(block, UI_EMBOSS);
  872. uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
  873. /* up/down */
  874. if (show_upbut || show_downbut) {
  875. uiBlockBeginAlign(block);
  876. if (show_upbut)
  877. uiItemO(row, "", ICON_TRIA_UP, "CONSTRAINT_OT_move_up");
  878. if (show_downbut)
  879. uiItemO(row, "", ICON_TRIA_DOWN, "CONSTRAINT_OT_move_down");
  880. uiBlockEndAlign(block);
  881. }
  882. /* Close 'button' - emboss calls here disable drawing of 'button' behind X */
  883. uiBlockSetEmboss(block, UI_EMBOSSN);
  884. uiItemO(row, "", ICON_X, "CONSTRAINT_OT_delete");
  885. uiBlockSetEmboss(block, UI_EMBOSS);
  886. }
  887. /* Set but-locks for protected settings (magic numbers are used here!) */
  888. if (proxy_protected)
  889. uiBlockSetButLock(block, 1, "Cannot edit Proxy-Protected Constraint");
  890. /* Draw constraint data */
  891. if ((con->flag & CONSTRAINT_EXPAND) == 0) {
  892. (yco) -= 21;
  893. }
  894. else {
  895. box = uiLayoutBox(col);
  896. block = uiLayoutAbsoluteBlock(box);
  897. result = box;
  898. }
  899. /* clear any locks set up for proxies/lib-linking */
  900. uiBlockClearButLock(block);
  901. return result;
  902. }
  903. uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr)
  904. {
  905. Object *ob;
  906. bConstraint *con;
  907. /* verify we have valid data */
  908. if (!RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
  909. RNA_warning("Expected constraint on object");
  910. return NULL;
  911. }
  912. ob = ptr->id.data;
  913. con = ptr->data;
  914. if (!ob || !(GS(ob->id.name) == ID_OB)) {
  915. RNA_warning("Expected constraint on object");
  916. return NULL;
  917. }
  918. uiBlockSetButLock(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
  919. /* hrms, the temporal constraint should not draw! */
  920. if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
  921. bKinematicConstraint *data = con->data;
  922. if (data->flag & CONSTRAINT_IK_TEMP)
  923. return NULL;
  924. }
  925. return draw_constraint(layout, ob, con);
  926. }
  927. /************************* Preview Template ***************************/
  928. #include "DNA_lamp_types.h"
  929. #include "DNA_material_types.h"
  930. #include "DNA_world_types.h"
  931. #define B_MATPRV 1
  932. static void do_preview_buttons(bContext *C, void *arg, int event)
  933. {
  934. switch (event) {
  935. case B_MATPRV:
  936. WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING, arg);
  937. break;
  938. }
  939. }
  940. void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot)
  941. {
  942. uiLayout *row, *col;
  943. uiBlock *block;
  944. Material *ma = NULL;
  945. Tex *tex = (Tex *)id;
  946. ID *pid, *pparent;
  947. short *pr_texture = NULL;
  948. PointerRNA material_ptr;
  949. PointerRNA texture_ptr;
  950. if (id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) {
  951. RNA_warning("Expected ID of type material, texture, lamp or world");
  952. return;
  953. }
  954. /* decide what to render */
  955. pid = id;
  956. pparent = NULL;
  957. if (id && (GS(id->name) == ID_TE)) {
  958. if (parent && (GS(parent->name) == ID_MA))
  959. pr_texture = &((Material *)parent)->pr_texture;
  960. else if (parent && (GS(parent->name) == ID_WO))
  961. pr_texture = &((World *)parent)->pr_texture;
  962. else if (parent && (GS(parent->name) == ID_LA))
  963. pr_texture = &((Lamp *)parent)->pr_texture;
  964. if (pr_texture) {
  965. if (*pr_texture == TEX_PR_OTHER)
  966. pid = parent;
  967. else if (*pr_texture == TEX_PR_BOTH)
  968. pparent = parent;
  969. }
  970. }
  971. /* layout */
  972. block = uiLayoutGetBlock(layout);
  973. row = uiLayoutRow(layout, 0);
  974. col = uiLayoutColumn(row, 0);
  975. uiLayoutSetKeepAspect(col, 1);
  976. /* add preview */
  977. uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, pid, 0.0, 0.0, 0, 0, "");
  978. uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
  979. uiBlockSetHandleFunc(block, do_preview_buttons, NULL);
  980. /* add buttons */
  981. if (pid && show_buttons) {
  982. if (GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {
  983. if (GS(pid->name) == ID_MA) ma = (Material *)pid;
  984. else ma = (Material *)pparent;
  985. /* Create RNA Pointer */
  986. RNA_pointer_create(id, &RNA_Material, ma, &material_ptr);
  987. col = uiLayoutColumn(row, 1);
  988. uiLayoutSetScaleX(col, 1.5);
  989. uiItemR(col, &material_ptr, "preview_render_type", UI_ITEM_R_EXPAND, "", ICON_NONE);
  990. }
  991. if (pr_texture) {
  992. /* Create RNA Pointer */
  993. RNA_pointer_create(id, &RNA_Texture, tex, &texture_ptr);
  994. uiLayoutRow(layout, 1);
  995. uiDefButS(block, ROW, B_MATPRV, IFACE_("Texture"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_TEXTURE, 0, 0, "");
  996. if (GS(parent->name) == ID_MA)
  997. uiDefButS(block, ROW, B_MATPRV, IFACE_("Material"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
  998. else if (GS(parent->name) == ID_LA)
  999. uiDefButS(block, ROW, B_MATPRV, IFACE_("Lamp"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
  1000. else if (GS(parent->name) == ID_WO)
  1001. uiDefButS(block, ROW, B_MATPRV, IFACE_("World"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_OTHER, 0, 0, "");
  1002. uiDefButS(block, ROW, B_MATPRV, IFACE_("Both"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, pr_texture, 10, TEX_PR_BOTH, 0, 0, "");
  1003. /* Alpha button for texture preview */
  1004. if (*pr_texture != TEX_PR_OTHER) {
  1005. row = uiLayoutRow(layout, 0);
  1006. uiItemR(row, &texture_ptr, "use_preview_alpha", 0, NULL, ICON_NONE);
  1007. }
  1008. }
  1009. }
  1010. }
  1011. /********************** ColorRamp Template **************************/
  1012. typedef struct RNAUpdateCb {
  1013. PointerRNA ptr;
  1014. PropertyRNA *prop;
  1015. } RNAUpdateCb;
  1016. static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
  1017. {
  1018. RNAUpdateCb *cb = (RNAUpdateCb *)arg_cb;
  1019. /* we call update here on the pointer property, this way the
  1020. * owner of the curve mapping can still define it's own update
  1021. * and notifier, even if the CurveMapping struct is shared. */
  1022. RNA_property_update(C, &cb->ptr, cb->prop);
  1023. }
  1024. #define B_BANDCOL 1
  1025. static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
  1026. {
  1027. ColorBand *coba = coba_v;
  1028. float pos = 0.5f;
  1029. if (coba->tot > 1) {
  1030. if (coba->cur > 0) pos = (coba->data[coba->cur - 1].pos + coba->data[coba->cur].pos) * 0.5f;
  1031. else pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f;
  1032. }
  1033. if (colorband_element_add(coba, pos)) {
  1034. rna_update_cb(C, cb_v, NULL);
  1035. ED_undo_push(C, "Add colorband");
  1036. }
  1037. }
  1038. static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
  1039. {
  1040. ColorBand *coba = coba_v;
  1041. if (colorband_element_remove(coba, coba->cur)) {
  1042. ED_undo_push(C, "Delete colorband");
  1043. rna_update_cb(C, cb_v, NULL);
  1044. }
  1045. }
  1046. static void colorband_flip_cb(bContext *C, void *cb_v, void *coba_v)
  1047. {
  1048. CBData data_tmp[MAXCOLORBAND];
  1049. ColorBand *coba = coba_v;
  1050. int a;
  1051. for (a = 0; a < coba->tot; a++) {
  1052. data_tmp[a] = coba->data[coba->tot - (a + 1)];
  1053. }
  1054. for (a = 0; a < coba->tot; a++) {
  1055. data_tmp[a].pos = 1.0f - data_tmp[a].pos;
  1056. coba->data[a] = data_tmp[a];
  1057. }
  1058. /* may as well flip the cur*/
  1059. coba->cur = coba->tot - (coba->cur + 1);
  1060. ED_undo_push(C, "Flip colorband");
  1061. rna_update_cb(C, cb_v, NULL);
  1062. }
  1063. static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
  1064. {
  1065. uiBut *bt = bt_v;
  1066. ColorBand *coba = coba_v;
  1067. /* sneaky update here, we need to sort the colorband points to be in order,
  1068. * however the RNA pointer then is wrong, so we update it */
  1069. colorband_update_sort(coba);
  1070. bt->rnapoin.data = coba->data + coba->cur;
  1071. }
  1072. /* offset aligns from bottom, standard width 300, height 115 */
  1073. static void colorband_buttons_large(uiLayout *layout, uiBlock *block, ColorBand *coba, int xoffs, int yoffs, RNAUpdateCb *cb)
  1074. {
  1075. uiBut *bt;
  1076. uiLayout *row;
  1077. const int line1_y = yoffs + 65 + UI_UNIT_Y + 2; /* 2 for some space between the buttons */
  1078. const int line2_y = yoffs + 65;
  1079. if (coba == NULL) return;
  1080. bt = uiDefBut(block, BUT, 0, IFACE_("Add"), 0 + xoffs, line1_y, 40, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  1081. TIP_("Add a new color stop to the colorband"));
  1082. uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
  1083. bt = uiDefBut(block, BUT, 0, IFACE_("Delete"), 45 + xoffs, line1_y, 45, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  1084. TIP_("Delete the active position"));
  1085. uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
  1086. /* XXX, todo for later - convert to operator - campbell */
  1087. bt = uiDefBut(block, BUT, 0, "F", 95 + xoffs, line1_y, 20, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip colorband"));
  1088. uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
  1089. uiDefButS(block, NUM, 0, "", 120 + xoffs, line1_y, 80, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)), 0, 0, TIP_("Choose active color stop"));
  1090. bt = uiDefButS(block, MENU, 0, IFACE_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
  1091. 210 + xoffs, line1_y, 90, UI_UNIT_Y, &coba->ipotype, 0.0, 0.0, 0, 0, TIP_("Set interpolation between color stops"));
  1092. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1093. uiBlockEndAlign(block);
  1094. bt = uiDefBut(block, BUT_COLORBAND, 0, "", xoffs, line2_y, 300, UI_UNIT_Y, coba, 0, 0, 0, 0, "");
  1095. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1096. if (coba->tot) {
  1097. CBData *cbd = coba->data + coba->cur;
  1098. /* better to use rna so we can animate them */
  1099. PointerRNA ptr;
  1100. RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
  1101. row = uiLayoutRow(layout, 0);
  1102. uiItemR(row, &ptr, "position", 0, "Pos", ICON_NONE);
  1103. bt = block->buttons.last;
  1104. uiButSetFunc(bt, colorband_update_cb, bt, coba);
  1105. uiItemR(row, &ptr, "color", 0, "", ICON_NONE);
  1106. }
  1107. }
  1108. static void colorband_buttons_small(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, RNAUpdateCb *cb)
  1109. {
  1110. uiBut *bt;
  1111. float unit = (butr->xmax - butr->xmin) / 14.0f;
  1112. float xs = butr->xmin;
  1113. uiBlockBeginAlign(block);
  1114. bt = uiDefBut(block, BUT, 0, IFACE_("Add"), xs, butr->ymin + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  1115. TIP_("Add a new color stop to the colorband"));
  1116. uiButSetNFunc(bt, colorband_add_cb, MEM_dupallocN(cb), coba);
  1117. bt = uiDefBut(block, BUT, 0, IFACE_("Delete"), xs + 2.0f * unit, butr->ymin + UI_UNIT_Y, 1.5f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0,
  1118. TIP_("Delete the active position"));
  1119. uiButSetNFunc(bt, colorband_del_cb, MEM_dupallocN(cb), coba);
  1120. bt = uiDefBut(block, BUT, 0, "F", xs + 3.5f * unit, butr->ymin + UI_UNIT_Y, 0.5f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip the color ramp"));
  1121. uiButSetNFunc(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
  1122. uiBlockEndAlign(block);
  1123. if (coba->tot) {
  1124. CBData *cbd = coba->data + coba->cur;
  1125. PointerRNA ptr;
  1126. RNA_pointer_create(cb->ptr.id.data, &RNA_ColorRampElement, cbd, &ptr);
  1127. uiItemR(layout, &ptr, "color", 0, "", ICON_NONE);
  1128. }
  1129. bt = uiDefButS(block, MENU, 0, TIP_("Interpolation %t|Ease %x1|Cardinal %x3|Linear %x0|B-Spline %x2|Constant %x4"),
  1130. xs + 10.0f * unit, butr->ymin + UI_UNIT_Y, unit * 4, UI_UNIT_Y, &coba->ipotype, 0.0, 0.0, 0, 0,
  1131. TIP_("Set interpolation between color stops"));
  1132. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1133. bt = uiDefBut(block, BUT_COLORBAND, 0, "", xs, butr->ymin, butr->xmax - butr->xmin, UI_UNIT_Y, coba, 0, 0, 0, 0, "");
  1134. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1135. uiBlockEndAlign(block);
  1136. }
  1137. static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand *coba, rctf *butr, int small, RNAUpdateCb *cb)
  1138. {
  1139. if (small)
  1140. colorband_buttons_small(layout, block, coba, butr, cb);
  1141. else
  1142. colorband_buttons_large(layout, block, coba, 0, 0, cb);
  1143. }
  1144. void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname, int expand)
  1145. {
  1146. PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  1147. PointerRNA cptr;
  1148. RNAUpdateCb *cb;
  1149. uiBlock *block;
  1150. rctf rect;
  1151. if (!prop || RNA_property_type(prop) != PROP_POINTER)
  1152. return;
  1153. cptr = RNA_property_pointer_get(ptr, prop);
  1154. if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_ColorRamp))
  1155. return;
  1156. cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
  1157. cb->ptr = *ptr;
  1158. cb->prop = prop;
  1159. rect.xmin = 0; rect.xmax = 200;
  1160. rect.ymin = 0; rect.ymax = 190;
  1161. block = uiLayoutAbsoluteBlock(layout);
  1162. colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
  1163. MEM_freeN(cb);
  1164. }
  1165. /********************* Histogram Template ************************/
  1166. void uiTemplateHistogram(uiLayout *layout, PointerRNA *ptr, const char *propname)
  1167. {
  1168. PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  1169. PointerRNA cptr;
  1170. RNAUpdateCb *cb;
  1171. uiBlock *block;
  1172. uiBut *bt;
  1173. Histogram *hist;
  1174. rctf rect;
  1175. if (!prop || RNA_property_type(prop) != PROP_POINTER)
  1176. return;
  1177. cptr = RNA_property_pointer_get(ptr, prop);
  1178. if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Histogram))
  1179. return;
  1180. cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
  1181. cb->ptr = *ptr;
  1182. cb->prop = prop;
  1183. rect.xmin = 0; rect.xmax = 200;
  1184. rect.ymin = 0; rect.ymax = 190;
  1185. block = uiLayoutAbsoluteBlock(layout);
  1186. //colorband_buttons_layout(layout, block, cptr.data, &rect, !expand, cb);
  1187. hist = (Histogram *)cptr.data;
  1188. hist->height = (hist->height <= UI_UNIT_Y) ? UI_UNIT_Y : hist->height;
  1189. bt = uiDefBut(block, HISTOGRAM, 0, "", rect.xmin, rect.ymin, rect.xmax - rect.xmin, hist->height, hist, 0, 0, 0, 0, "");
  1190. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1191. MEM_freeN(cb);
  1192. }
  1193. /********************* Waveform Template ************************/
  1194. void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
  1195. {
  1196. PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  1197. PointerRNA cptr;
  1198. RNAUpdateCb *cb;
  1199. uiBlock *block;
  1200. uiBut *bt;
  1201. Scopes *scopes;
  1202. rctf rect;
  1203. if (!prop || RNA_property_type(prop) != PROP_POINTER)
  1204. return;
  1205. cptr = RNA_property_pointer_get(ptr, prop);
  1206. if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
  1207. return;
  1208. scopes = (Scopes *)cptr.data;
  1209. cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
  1210. cb->ptr = *ptr;
  1211. cb->prop = prop;
  1212. rect.xmin = 0; rect.xmax = 200;
  1213. rect.ymin = 0; rect.ymax = 190;
  1214. block = uiLayoutAbsoluteBlock(layout);
  1215. scopes->wavefrm_height = (scopes->wavefrm_height <= UI_UNIT_Y) ? UI_UNIT_Y : scopes->wavefrm_height;
  1216. bt = uiDefBut(block, WAVEFORM, 0, "", rect.xmin, rect.ymin, rect.xmax - rect.xmin, scopes->wavefrm_height, scopes, 0, 0, 0, 0, "");
  1217. (void)bt; // UNUSED
  1218. MEM_freeN(cb);
  1219. }
  1220. /********************* Vectorscope Template ************************/
  1221. void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
  1222. {
  1223. PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  1224. PointerRNA cptr;
  1225. RNAUpdateCb *cb;
  1226. uiBlock *block;
  1227. uiBut *bt;
  1228. Scopes *scopes;
  1229. rctf rect;
  1230. if (!prop || RNA_property_type(prop) != PROP_POINTER)
  1231. return;
  1232. cptr = RNA_property_pointer_get(ptr, prop);
  1233. if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Scopes))
  1234. return;
  1235. scopes = (Scopes *)cptr.data;
  1236. cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
  1237. cb->ptr = *ptr;
  1238. cb->prop = prop;
  1239. rect.xmin = 0; rect.xmax = 200;
  1240. rect.ymin = 0; rect.ymax = 190;
  1241. block = uiLayoutAbsoluteBlock(layout);
  1242. scopes->vecscope_height = (scopes->vecscope_height <= UI_UNIT_Y) ? UI_UNIT_Y : scopes->vecscope_height;
  1243. bt = uiDefBut(block, VECTORSCOPE, 0, "", rect.xmin, rect.ymin, rect.xmax - rect.xmin, scopes->vecscope_height, scopes, 0, 0, 0, 0, "");
  1244. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1245. MEM_freeN(cb);
  1246. }
  1247. /********************* CurveMapping Template ************************/
  1248. static void curvemap_buttons_zoom_in(bContext *C, void *cumap_v, void *UNUSED(arg))
  1249. {
  1250. CurveMapping *cumap = cumap_v;
  1251. float d;
  1252. /* we allow 20 times zoom */
  1253. if ( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f * (cumap->clipr.xmax - cumap->clipr.xmin) ) {
  1254. d = 0.1154f * (cumap->curr.xmax - cumap->curr.xmin);
  1255. cumap->curr.xmin += d;
  1256. cumap->curr.xmax -= d;
  1257. d = 0.1154f * (cumap->curr.ymax - cumap->curr.ymin);
  1258. cumap->curr.ymin += d;
  1259. cumap->curr.ymax -= d;
  1260. }
  1261. ED_region_tag_redraw(CTX_wm_region(C));
  1262. }
  1263. static void curvemap_buttons_zoom_out(bContext *C, void *cumap_v, void *UNUSED(unused))
  1264. {
  1265. CurveMapping *cumap = cumap_v;
  1266. float d, d1;
  1267. /* we allow 20 times zoom, but don't view outside clip */
  1268. if ( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f * (cumap->clipr.xmax - cumap->clipr.xmin) ) {
  1269. d = d1 = 0.15f * (cumap->curr.xmax - cumap->curr.xmin);
  1270. if (cumap->flag & CUMA_DO_CLIP)
  1271. if (cumap->curr.xmin - d < cumap->clipr.xmin)
  1272. d1 = cumap->curr.xmin - cumap->clipr.xmin;
  1273. cumap->curr.xmin -= d1;
  1274. d1 = d;
  1275. if (cumap->flag & CUMA_DO_CLIP)
  1276. if (cumap->curr.xmax + d > cumap->clipr.xmax)
  1277. d1 = -cumap->curr.xmax + cumap->clipr.xmax;
  1278. cumap->curr.xmax += d1;
  1279. d = d1 = 0.15f * (cumap->curr.ymax - cumap->curr.ymin);
  1280. if (cumap->flag & CUMA_DO_CLIP)
  1281. if (cumap->curr.ymin - d < cumap->clipr.ymin)
  1282. d1 = cumap->curr.ymin - cumap->clipr.ymin;
  1283. cumap->curr.ymin -= d1;
  1284. d1 = d;
  1285. if (cumap->flag & CUMA_DO_CLIP)
  1286. if (cumap->curr.ymax + d > cumap->clipr.ymax)
  1287. d1 = -cumap->curr.ymax + cumap->clipr.ymax;
  1288. cumap->curr.ymax += d1;
  1289. }
  1290. ED_region_tag_redraw(CTX_wm_region(C));
  1291. }
  1292. static void curvemap_buttons_setclip(bContext *UNUSED(C), void *cumap_v, void *UNUSED(arg))
  1293. {
  1294. CurveMapping *cumap = cumap_v;
  1295. curvemapping_changed(cumap, 0);
  1296. }
  1297. static void curvemap_buttons_delete(bContext *C, void *cb_v, void *cumap_v)
  1298. {
  1299. CurveMapping *cumap = cumap_v;
  1300. curvemap_remove(cumap->cm + cumap->cur, SELECT);
  1301. curvemapping_changed(cumap, 0);
  1302. rna_update_cb(C, cb_v, NULL);
  1303. }
  1304. /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
  1305. static uiBlock *curvemap_clipping_func(bContext *C, struct ARegion *ar, void *cumap_v)
  1306. {
  1307. CurveMapping *cumap = cumap_v;
  1308. uiBlock *block;
  1309. uiBut *bt;
  1310. float width = 8 * UI_UNIT_X;
  1311. block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
  1312. /* use this for a fake extra empy space around the buttons */
  1313. uiDefBut(block, LABEL, 0, "", -4, 16, width + 8, 6 * UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
  1314. bt = uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",
  1315. 0, 5 * UI_UNIT_Y, width, UI_UNIT_Y, &cumap->flag, 0.0, 0.0, 10, 0, "");
  1316. uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
  1317. uiBlockBeginAlign(block);
  1318. uiDefButF(block, NUM, 0, IFACE_("Min X "), 0, 4 * UI_UNIT_Y, width, UI_UNIT_Y, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
  1319. uiDefButF(block, NUM, 0, IFACE_("Min Y "), 0, 3 * UI_UNIT_Y, width, UI_UNIT_Y, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
  1320. uiDefButF(block, NUM, 0, IFACE_("Max X "), 0, 2 * UI_UNIT_Y, width, UI_UNIT_Y, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
  1321. uiDefButF(block, NUM, 0, IFACE_("Max Y "), 0, UI_UNIT_Y, width, UI_UNIT_Y, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
  1322. uiBlockSetDirection(block, UI_RIGHT);
  1323. uiEndBlock(C, block);
  1324. return block;
  1325. }
  1326. static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
  1327. {
  1328. CurveMapping *cumap = cumap_v;
  1329. CurveMap *cuma = cumap->cm + cumap->cur;
  1330. switch (event) {
  1331. case 0: /* reset */
  1332. curvemap_reset(cuma, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
  1333. curvemapping_changed(cumap, 0);
  1334. break;
  1335. case 1:
  1336. cumap->curr = cumap->clipr;
  1337. break;
  1338. case 2: /* set vector */
  1339. curvemap_sethandle(cuma, 1);
  1340. curvemapping_changed(cumap, 0);
  1341. break;
  1342. case 3: /* set auto */
  1343. curvemap_sethandle(cuma, 0);
  1344. curvemapping_changed(cumap, 0);
  1345. break;
  1346. case 4: /* extend horiz */
  1347. cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
  1348. curvemapping_changed(cumap, 0);
  1349. break;
  1350. case 5: /* extend extrapolate */
  1351. cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
  1352. curvemapping_changed(cumap, 0);
  1353. break;
  1354. }
  1355. ED_region_tag_redraw(CTX_wm_region(C));
  1356. }
  1357. static uiBlock *curvemap_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
  1358. {
  1359. uiBlock *block;
  1360. short yco = 0, menuwidth = 10 * UI_UNIT_X;
  1361. block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
  1362. uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
  1363. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
  1364. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
  1365. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
  1366. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 4, "");
  1367. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 5, "");
  1368. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
  1369. uiBlockSetDirection(block, UI_RIGHT);
  1370. uiTextBoundsBlock(block, 50);
  1371. uiEndBlock(C, block);
  1372. return block;
  1373. }
  1374. static uiBlock *curvemap_brush_tools_func(bContext *C, struct ARegion *ar, void *cumap_v)
  1375. {
  1376. uiBlock *block;
  1377. short yco = 0, menuwidth = 10 * UI_UNIT_X;
  1378. block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
  1379. uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
  1380. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 1, "");
  1381. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 2, "");
  1382. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 3, "");
  1383. uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
  1384. uiBlockSetDirection(block, UI_RIGHT);
  1385. uiTextBoundsBlock(block, 50);
  1386. uiEndBlock(C, block);
  1387. return block;
  1388. }
  1389. static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
  1390. {
  1391. ED_region_tag_redraw(CTX_wm_region(C));
  1392. }
  1393. static void curvemap_buttons_reset(bContext *C, void *cb_v, void *cumap_v)
  1394. {
  1395. CurveMapping *cumap = cumap_v;
  1396. int a;
  1397. cumap->preset = CURVE_PRESET_LINE;
  1398. for (a = 0; a < CM_TOT; a++)
  1399. curvemap_reset(cumap->cm + a, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE);
  1400. cumap->black[0] = cumap->black[1] = cumap->black[2] = 0.0f;
  1401. cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
  1402. curvemapping_set_black_white(cumap, NULL, NULL);
  1403. curvemapping_changed(cumap, 0);
  1404. rna_update_cb(C, cb_v, NULL);
  1405. }
  1406. /* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
  1407. static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labeltype, int levels, int brush, RNAUpdateCb *cb)
  1408. {
  1409. CurveMapping *cumap = ptr->data;
  1410. uiLayout *row, *sub, *split;
  1411. uiBlock *block;
  1412. uiBut *bt;
  1413. float dx = UI_UNIT_X;
  1414. int icon, size;
  1415. int bg = -1;
  1416. block = uiLayoutGetBlock(layout);
  1417. /* curve chooser */
  1418. row = uiLayoutRow(layout, 0);
  1419. if (labeltype == 'v') {
  1420. /* vector */
  1421. sub = uiLayoutRow(row, 1);
  1422. uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
  1423. if (cumap->cm[0].curve) {
  1424. bt = uiDefButI(block, ROW, 0, "X", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
  1425. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1426. }
  1427. if (cumap->cm[1].curve) {
  1428. bt = uiDefButI(block, ROW, 0, "Y", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
  1429. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1430. }
  1431. if (cumap->cm[2].curve) {
  1432. bt = uiDefButI(block, ROW, 0, "Z", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
  1433. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1434. }
  1435. }
  1436. else if (labeltype == 'c') {
  1437. /* color */
  1438. sub = uiLayoutRow(row, 1);
  1439. uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
  1440. if (cumap->cm[3].curve) {
  1441. bt = uiDefButI(block, ROW, 0, "C", 0, 0, dx, dx, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
  1442. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1443. }
  1444. if (cumap->cm[0].curve) {
  1445. bt = uiDefButI(block, ROW, 0, "R", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
  1446. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1447. }
  1448. if (cumap->cm[1].curve) {
  1449. bt = uiDefButI(block, ROW, 0, "G", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
  1450. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1451. }
  1452. if (cumap->cm[2].curve) {
  1453. bt = uiDefButI(block, ROW, 0, "B", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
  1454. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1455. }
  1456. }
  1457. else if (labeltype == 'h') {
  1458. /* HSV */
  1459. sub = uiLayoutRow(row, 1);
  1460. uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
  1461. if (cumap->cm[0].curve) {
  1462. bt = uiDefButI(block, ROW, 0, "H", 0, 0, dx, dx, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
  1463. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1464. }
  1465. if (cumap->cm[1].curve) {
  1466. bt = uiDefButI(block, ROW, 0, "S", 0, 0, dx, dx, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
  1467. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1468. }
  1469. if (cumap->cm[2].curve) {
  1470. bt = uiDefButI(block, ROW, 0, "V", 0, 0, dx, dx, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
  1471. uiButSetFunc(bt, curvemap_buttons_redraw, NULL, NULL);
  1472. }
  1473. }
  1474. else
  1475. uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
  1476. if (labeltype == 'h')
  1477. bg = UI_GRAD_H;
  1478. /* operation buttons */
  1479. sub = uiLayoutRow(row, 1);
  1480. uiBlockSetEmboss(block, UI_EMBOSSN);
  1481. bt = uiDefIconBut(block, BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
  1482. uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
  1483. bt = uiDefIconBut(block, BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
  1484. uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
  1485. if (brush)
  1486. bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
  1487. else
  1488. bt = uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
  1489. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1490. if (cumap->flag & CUMA_DO_CLIP) icon = ICON_CLIPUV_HLT; else icon = ICON_CLIPUV_DEHLT;
  1491. bt = uiDefIconBlockBut(block, curvemap_clipping_func, cumap, 0, icon, 0, 0, dx, dx, TIP_("Clipping Options"));
  1492. uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
  1493. bt = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete points"));
  1494. uiButSetNFunc(bt, curvemap_buttons_delete, MEM_dupallocN(cb), cumap);
  1495. uiBlockSetEmboss(block, UI_EMBOSS);
  1496. uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
  1497. /* curve itself */
  1498. size = uiLayoutGetWidth(layout);
  1499. row = uiLayoutRow(layout, 0);
  1500. uiDefBut(block, BUT_CURVE, 0, "", 0, 0, size, MIN2(size, 200), cumap, 0.0f, 1.0f, bg, 0, "");
  1501. /* black/white levels */
  1502. if (levels) {
  1503. split = uiLayoutSplit(layout, 0, 0);
  1504. uiItemR(uiLayoutColumn(split, 0), ptr, "black_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
  1505. uiItemR(uiLayoutColumn(split, 0), ptr, "white_level", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
  1506. uiLayoutRow(layout, 0);
  1507. bt = uiDefBut(block, BUT, 0, IFACE_("Reset"), 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
  1508. TIP_("Reset Black/White point and curves"));
  1509. uiButSetNFunc(bt, curvemap_buttons_reset, MEM_dupallocN(cb), cumap);
  1510. }
  1511. uiBlockSetNFunc(block, NULL, NULL, NULL);
  1512. }
  1513. void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
  1514. {
  1515. RNAUpdateCb *cb;
  1516. PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  1517. PointerRNA cptr;
  1518. if (!prop) {
  1519. RNA_warning("curve property not found: %s.%s",
  1520. RNA_struct_identifier(ptr->type), propname);
  1521. return;
  1522. }
  1523. if (RNA_property_type(prop) != PROP_POINTER) {
  1524. RNA_warning("curve is not a pointer: %s.%s",
  1525. RNA_struct_identifier(ptr->type), propname);
  1526. return;
  1527. }
  1528. cptr = RNA_property_pointer_get(ptr, prop);
  1529. if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveMapping))
  1530. return;
  1531. cb = MEM_callocN(sizeof(RNAUpdateCb), "RNAUpdateCb");
  1532. cb->ptr = *ptr;
  1533. cb->prop = prop;
  1534. curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
  1535. MEM_freeN(cb);
  1536. }
  1537. /********************* ColorWheel Template ************************/
  1538. #define WHEEL_SIZE 100
  1539. void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic)
  1540. {
  1541. PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  1542. uiBlock *block = uiLayoutGetBlock(layout);
  1543. uiLayout *col, *row;
  1544. uiBut *but;
  1545. float softmin, softmax, step, precision;
  1546. if (!prop) {
  1547. RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
  1548. return;
  1549. }
  1550. RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
  1551. col = uiLayoutColumn(layout, 0);
  1552. row = uiLayoutRow(col, 1);
  1553. but = uiDefButR_prop(block, HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, "");
  1554. if (lock) {
  1555. but->flag |= UI_BUT_COLOR_LOCK;
  1556. }
  1557. if (lock_luminosity) {
  1558. float color[4]; /* in case of alpha */
  1559. but->flag |= UI_BUT_VEC_SIZE_LOCK;
  1560. RNA_property_float_get_array(ptr, prop, color);
  1561. but->a2 = len_v3(color);
  1562. }
  1563. if (cubic)
  1564. but->flag |= UI_BUT_COLOR_CUBIC;
  1565. uiItemS(row);
  1566. if (value_slider)
  1567. uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, "");
  1568. }
  1569. /********************* Layer Buttons Template ************************/
  1570. static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
  1571. {
  1572. uiBut *but = arg1;
  1573. int cur = GET_INT_FROM_POINTER(arg2);
  1574. wmWindow *win = CTX_wm_window(C);
  1575. int i, tot, shift = win->eventstate->shift;
  1576. if (!shift) {
  1577. tot = RNA_property_array_length(&but->rnapoin, but->rnaprop);
  1578. /* Normally clicking only selects one layer */
  1579. RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, cur, TRUE);
  1580. for (i = 0; i < tot; ++i) {
  1581. if (i != cur)
  1582. RNA_property_boolean_set_index(&but->rnapoin, but->rnaprop, i, FALSE);
  1583. }
  1584. }
  1585. /* view3d layer change should update depsgraph (invisible object changed maybe) */
  1586. /* see view3d_header.c */
  1587. }
  1588. // TODO:
  1589. // - for now, grouping of layers is determined by dividing up the length of
  1590. // the array of layer bitflags
  1591. void uiTemplateLayers(uiLayout *layout, PointerRNA *ptr, const char *propname,
  1592. PointerRNA *used_ptr, const char *used_propname, int active_layer)
  1593. {
  1594. uiLayout *uRow, *uCol;
  1595. PropertyRNA *prop, *used_prop = NULL;
  1596. int groups, cols, layers;
  1597. int group, col, layer, row;
  1598. int cols_per_group = 5;
  1599. prop = RNA_struct_find_property(ptr, propname);
  1600. if (!prop) {
  1601. RNA_warning("layers property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
  1602. return;
  1603. }
  1604. /* the number of layers determines the way we group them
  1605. * - we want 2 rows only (for now)
  1606. * - the number of columns (cols) is the total number of buttons per row
  1607. * the 'remainder' is added to this, as it will be ok to have first row slightly wider if need be
  1608. * - for now, only split into groups if group will have at least 5 items
  1609. */
  1610. layers = RNA_property_array_length(ptr, prop);
  1611. cols = (layers / 2) + (layers % 2);
  1612. groups = ((cols / 2) < cols_per_group) ? (1) : (cols / cols_per_group);
  1613. if (used_ptr && used_propname) {
  1614. used_prop = RNA_struct_find_property(used_ptr, used_propname);
  1615. if (!used_prop) {
  1616. RNA_warning("used layers property not found: %s.%s", RNA_struct_identifier(ptr->type), used_propname);
  1617. return;
  1618. }
  1619. if (RNA_property_array_length(used_ptr, used_prop) < layers)
  1620. used_prop = NULL;
  1621. }
  1622. /* layers are laid out going across rows, with the columns being divided into groups */
  1623. for (group = 0; group < groups; group++) {
  1624. uCol = uiLayoutColumn(layout, 1);
  1625. for (row = 0; row < 2; row++) {
  1626. uiBlock *block;
  1627. uiBut *but;
  1628. uRow = uiLayoutRow(uCol, 1);
  1629. block = uiLayoutGetBlock(uRow);
  1630. layer = groups * cols_per_group * row + cols_per_group * group;
  1631. /* add layers as toggle buts */
  1632. for (col = 0; (col < cols_per_group) && (layer < layers); col++, layer++) {
  1633. int icon = 0;
  1634. int butlay = 1 << layer;
  1635. if (active_layer & butlay)
  1636. icon = ICON_LAYER_ACTIVE;
  1637. else if (used_prop && RNA_property_boolean_get_index(used_ptr, used_prop, layer))
  1638. icon = ICON_LAYER_USED;
  1639. but = uiDefAutoButR(block, ptr, prop, layer, "", icon, 0, 0, UI_UNIT_X / 2, UI_UNIT_Y / 2);
  1640. uiButSetFunc(but, handle_layer_buttons, but, SET_INT_IN_POINTER(layer));
  1641. but->type = TOG;
  1642. }
  1643. }
  1644. }
  1645. }
  1646. /************************* List Template **************************/
  1647. static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
  1648. {
  1649. ID *id = NULL;
  1650. int icon;
  1651. if (!itemptr->data)
  1652. return rnaicon;
  1653. /* try ID, material or texture slot */
  1654. if (RNA_struct_is_ID(itemptr->type)) {
  1655. id = itemptr->id.data;
  1656. }
  1657. else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
  1658. id = RNA_pointer_get(itemptr, "material").data;
  1659. }
  1660. else if (RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
  1661. id = RNA_pointer_get(itemptr, "texture").data;
  1662. }
  1663. else if (RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
  1664. DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
  1665. if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
  1666. else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
  1667. else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
  1668. }
  1669. /* get icon from ID */
  1670. if (id) {
  1671. icon = ui_id_icon_get(C, id, big);
  1672. if (icon)
  1673. return icon;
  1674. }
  1675. return rnaicon;
  1676. }
  1677. static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop, const char *prop_list_id)
  1678. {
  1679. uiBlock *block = uiLayoutGetBlock(layout);
  1680. uiBut *but;
  1681. uiLayout *split, *overlap, *sub, *row;
  1682. char *namebuf;
  1683. const char *name;
  1684. int icon;
  1685. overlap = uiLayoutOverlap(layout);
  1686. /* list item behind label & other buttons */
  1687. sub = uiLayoutRow(overlap, 0);
  1688. but = uiDefButR_prop(block, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
  1689. uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
  1690. sub = uiLayoutRow(overlap, 0);
  1691. /* retrieve icon and name */
  1692. icon = list_item_icon_get(C, itemptr, rnaicon, 0);
  1693. if (icon == ICON_NONE || icon == ICON_DOT)
  1694. icon = 0;
  1695. namebuf = RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL);
  1696. name = (namebuf) ? namebuf : "";
  1697. /* hardcoded types */
  1698. if (itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
  1699. uiItemL(sub, name, icon);
  1700. uiBlockSetEmboss(block, UI_EMBOSSN);
  1701. uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL);
  1702. uiBlockSetEmboss(block, UI_EMBOSS);
  1703. }
  1704. else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
  1705. uiItemL(sub, name, icon);
  1706. uiBlockSetEmboss(block, UI_EMBOSS);
  1707. uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0, NULL);
  1708. }
  1709. else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
  1710. uiItemL(sub, name, icon);
  1711. uiBlockSetEmboss(block, UI_EMBOSS);
  1712. uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL);
  1713. }
  1714. else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
  1715. /* provision to draw active node name */
  1716. Material *ma, *manode;
  1717. Scene *scene = CTX_data_scene(C);
  1718. Object *ob = (Object *)ptr->id.data;
  1719. int index = (Material **)itemptr->data - ob->mat;
  1720. /* default item with material base name */
  1721. uiItemL(sub, name, icon);
  1722. ma = give_current_material(ob, index + 1);
  1723. if (ma && !scene_use_new_shading_nodes(scene)) {
  1724. manode = give_node_material(ma);
  1725. if (manode) {
  1726. char str[MAX_ID_NAME + 12];
  1727. BLI_snprintf(str, sizeof(str), "Node %s", manode->id.name + 2);
  1728. uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
  1729. }
  1730. else if (ma->use_nodes) {
  1731. uiItemL(sub, "Node <none>", ICON_NONE);
  1732. }
  1733. }
  1734. }
  1735. else if (itemptr->type == &RNA_ShapeKey) {
  1736. Object *ob = (Object *)activeptr->data;
  1737. Key *key = (Key *)itemptr->id.data;
  1738. KeyBlock *kb = (KeyBlock *)itemptr->data;
  1739. split = uiLayoutSplit(sub, 0.66f, 0);
  1740. uiItemL(split, name, icon);
  1741. uiBlockSetEmboss(block, UI_EMBOSSN);
  1742. row = uiLayoutRow(split, 1);
  1743. if (i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
  1744. else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
  1745. uiItemR(row, itemptr, "mute", 0, "", 0);
  1746. if ((kb->flag & KEYBLOCK_MUTE) ||
  1747. (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH)))
  1748. {
  1749. uiLayoutSetActive(row, 0);
  1750. }
  1751. uiBlockSetEmboss(block, UI_EMBOSS);
  1752. }
  1753. else if (itemptr->type == &RNA_VertexGroup) {
  1754. bDeformGroup *dg = (bDeformGroup *)itemptr->data;
  1755. uiItemL(sub, name, icon);
  1756. /* RNA does not allow nice lock icons, use lower level buttons */
  1757. #if 0
  1758. uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0, NULL);
  1759. #else
  1760. uiBlockSetEmboss(block, UI_EMBOSSN);
  1761. uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED, 0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0, "Maintain relative weights while painting");
  1762. uiBlockSetEmboss(block, UI_EMBOSS);
  1763. #endif
  1764. }
  1765. else if (itemptr->type == &RNA_KeyingSetPath) {
  1766. KS_Path *ksp = (KS_Path *)itemptr->data;
  1767. /* icon needs to be the type of ID which is currently active */
  1768. RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
  1769. /* nothing else special to do... */
  1770. uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
  1771. }
  1772. else if (itemptr->type == &RNA_DynamicPaintSurface) {
  1773. char name_final[96];
  1774. const char *enum_name;
  1775. PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
  1776. DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
  1777. RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
  1778. BLI_snprintf(name_final, sizeof(name_final), "%s (%s)", name, enum_name);
  1779. uiItemL(sub, name_final, icon);
  1780. if (dynamicPaint_surfaceHasColorPreview(surface)) {
  1781. uiBlockSetEmboss(block, UI_EMBOSSN);
  1782. uiDefIconButR(block, OPTION, 0, (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
  1783. 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
  1784. uiBlockSetEmboss(block, UI_EMBOSS);
  1785. }
  1786. uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0, NULL);
  1787. }
  1788. else if (itemptr->type == &RNA_MovieTrackingObject) {
  1789. MovieTrackingObject *tracking_object = (MovieTrackingObject *)itemptr->data;
  1790. split = uiLayoutSplit(sub, 0.75f, 0);
  1791. if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
  1792. uiItemL(split, name, ICON_CAMERA_DATA);
  1793. }
  1794. else {
  1795. uiItemL(split, name, ICON_OBJECT_DATA);
  1796. }
  1797. }
  1798. /* There is a last chance to display custom controls (in addition to the name/label):
  1799. * If the given item property group features a string property named as prop_list,
  1800. * this tries to add controls for all properties of the item listed in that string property.
  1801. * (colon-separated names).
  1802. *
  1803. * This is especially useful for python. E.g., if you list a collection of this property
  1804. * group:
  1805. *
  1806. * class TestPropertyGroup(bpy.types.PropertyGroup):
  1807. * bool = BoolProperty(default=False)
  1808. * integer = IntProperty()
  1809. * string = StringProperty()
  1810. *
  1811. * # A string of all identifiers (colon-separated) which property's controls should be
  1812. * # displayed in a template_list.
  1813. * template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"})
  1814. *
  1815. * ... you'll get a numfield for the integer prop, a check box for the bool prop, and a textfield
  1816. * for the string prop, after the name of each item of the collection.
  1817. */
  1818. else if (prop_list_id) {
  1819. row = uiLayoutRow(sub, 1);
  1820. uiItemL(row, name, icon);
  1821. /* XXX: Check, as sometimes we get an itemptr looking like
  1822. * {id = {data = 0x0}, type = 0x0, data = 0x0}
  1823. * which would obviously produce a sigsev... */
  1824. if (itemptr->type) {
  1825. /* If the special property is set for the item, and it is a collection... */
  1826. PropertyRNA *prop_list = RNA_struct_find_property(itemptr, prop_list_id);
  1827. if (prop_list && RNA_property_type(prop_list) == PROP_STRING) {
  1828. int prop_names_len;
  1829. char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len);
  1830. char *prop_names_end = prop_names + prop_names_len;
  1831. char *id = prop_names;
  1832. char *id_next;
  1833. while (id < prop_names_end) {
  1834. if ((id_next = strchr(id, ':'))) *id_next++ = '\0';
  1835. else id_next = prop_names_end;
  1836. uiItemR(row, itemptr, id, 0, NULL, 0);
  1837. id = id_next;
  1838. }
  1839. MEM_freeN(prop_names);
  1840. }
  1841. }
  1842. }
  1843. else
  1844. uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
  1845. /* free name */
  1846. if (namebuf) {
  1847. MEM_freeN(namebuf);
  1848. }
  1849. }
  1850. void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, const char *activepropname, const char *prop_list, int rows, int maxrows, int listtype)
  1851. {
  1852. //Scene *scene= CTX_data_scene(C);
  1853. PropertyRNA *prop = NULL, *activeprop;
  1854. PropertyType type, activetype;
  1855. StructRNA *ptype;
  1856. uiLayout *box, *row, *col;
  1857. uiBlock *block;
  1858. uiBut *but;
  1859. Panel *pa;
  1860. const char *name;
  1861. char numstr[32];
  1862. int rnaicon = 0, icon = 0, i = 0, activei = 0, len = 0, items, found, min, max;
  1863. /* validate arguments */
  1864. block = uiLayoutGetBlock(layout);
  1865. pa = block->panel;
  1866. if (!pa) {
  1867. RNA_warning("Only works inside a panel");
  1868. return;
  1869. }
  1870. if (!activeptr->data)
  1871. return;
  1872. if (ptr->data) {
  1873. prop = RNA_struct_find_property(ptr, propname);
  1874. if (!prop) {
  1875. RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
  1876. return;
  1877. }
  1878. }
  1879. activeprop = RNA_struct_find_property(activeptr, activepropname);
  1880. if (!activeprop) {
  1881. RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
  1882. return;
  1883. }
  1884. if (prop) {
  1885. type = RNA_property_type(prop);
  1886. if (type != PROP_COLLECTION) {
  1887. RNA_warning("uiExpected collection property");
  1888. return;
  1889. }
  1890. }
  1891. activetype = RNA_property_type(activeprop);
  1892. if (activetype != PROP_INT) {
  1893. RNA_warning("Expected integer property");
  1894. return;
  1895. }
  1896. /* get icon */
  1897. if (ptr->data && prop) {
  1898. ptype = RNA_property_pointer_type(ptr, prop);
  1899. rnaicon = RNA_struct_ui_icon(ptype);
  1900. }
  1901. /* get active data */
  1902. activei = RNA_property_int_get(activeptr, activeprop);
  1903. if (listtype == 'i') {
  1904. box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
  1905. col = uiLayoutColumn(box, 1);
  1906. row = uiLayoutRow(col, 0);
  1907. if (ptr->data && prop) {
  1908. /* create list items */
  1909. RNA_PROP_BEGIN(ptr, itemptr, prop) {
  1910. /* create button */
  1911. if (!(i % 9))
  1912. row = uiLayoutRow(col, 0);
  1913. icon = list_item_icon_get(C, &itemptr, rnaicon, 1);
  1914. but = uiDefIconButR_prop(block, LISTROW, 0, icon, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop, 0, 0, i, 0, 0, "");
  1915. uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
  1916. i++;
  1917. }
  1918. RNA_PROP_END;
  1919. }
  1920. }
  1921. else if (listtype == 'c') {
  1922. /* compact layout */
  1923. row = uiLayoutRow(layout, 1);
  1924. if (ptr->data && prop) {
  1925. /* create list items */
  1926. RNA_PROP_BEGIN(ptr, itemptr, prop) {
  1927. found = (activei == i);
  1928. if (found) {
  1929. /* create button */
  1930. name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
  1931. icon = list_item_icon_get(C, &itemptr, rnaicon, 0);
  1932. uiItemL(row, (name) ? name : "", icon);
  1933. if (name) {
  1934. MEM_freeN((void *)name);
  1935. }
  1936. }
  1937. i++;
  1938. }
  1939. RNA_PROP_END;
  1940. }
  1941. /* if not found, add in dummy button */
  1942. if (i == 0)
  1943. uiItemL(row, "", ICON_NONE);
  1944. /* next/prev button */
  1945. BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
  1946. but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, activeptr, activeprop, 0, 0, 0, 0, 0, "");
  1947. if (i == 0)
  1948. uiButSetFlag(but, UI_BUT_DISABLED);
  1949. }
  1950. else {
  1951. /* default rows */
  1952. if (rows == 0)
  1953. rows = 5;
  1954. if (maxrows == 0)
  1955. maxrows = 5;
  1956. if (pa->list_grip_size != 0)
  1957. rows = pa->list_grip_size;
  1958. /* layout */
  1959. box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
  1960. row = uiLayoutRow(box, 0);
  1961. col = uiLayoutColumn(row, 1);
  1962. /* init numbers */
  1963. RNA_property_int_range(activeptr, activeprop, &min, &max);
  1964. if (prop)
  1965. len = RNA_property_collection_length(ptr, prop);
  1966. items = CLAMPIS(len, rows, MAX2(rows, maxrows));
  1967. /* if list length changes and active is out of view, scroll to it */
  1968. if (pa->list_last_len != len)
  1969. if ((activei < pa->list_scroll || activei >= pa->list_scroll + items))
  1970. pa->list_scroll = activei;
  1971. pa->list_scroll = MIN2(pa->list_scroll, len - items);
  1972. pa->list_scroll = MAX2(pa->list_scroll, 0);
  1973. pa->list_size = items;
  1974. pa->list_last_len = len;
  1975. if (ptr->data && prop) {
  1976. /* create list items */
  1977. RNA_PROP_BEGIN(ptr, itemptr, prop) {
  1978. if (i >= pa->list_scroll && i < pa->list_scroll + items)
  1979. list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list);
  1980. i++;
  1981. }
  1982. RNA_PROP_END;
  1983. }
  1984. /* add dummy buttons to fill space */
  1985. while (i < pa->list_scroll + items) {
  1986. if (i >= pa->list_scroll)
  1987. uiItemL(col, "", ICON_NONE);
  1988. i++;
  1989. }
  1990. /* add scrollbar */
  1991. if (len > items) {
  1992. col = uiLayoutColumn(row, 0);
  1993. uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &pa->list_scroll, 0, len - items, items, 0, "");
  1994. }
  1995. }
  1996. }
  1997. /************************* Operator Search Template **************************/
  1998. static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
  1999. {
  2000. wmOperatorType *ot = arg2;
  2001. if (ot)
  2002. WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
  2003. }
  2004. static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
  2005. {
  2006. GHashIterator *iter = WM_operatortype_iter();
  2007. for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
  2008. wmOperatorType *ot = BLI_ghashIterator_getValue(iter);
  2009. if (BLI_strcasestr(ot->name, str)) {
  2010. if (WM_operator_poll((bContext *)C, ot)) {
  2011. char name[256];
  2012. int len = strlen(ot->name);
  2013. /* display name for menu, can hold hotkey */
  2014. BLI_strncpy(name, ot->name, sizeof(name));
  2015. /* check for hotkey */
  2016. if (len < sizeof(name) - 6) {
  2017. if (WM_key_event_operator_string(C, ot->idname, WM_OP_EXEC_DEFAULT, NULL, TRUE,
  2018. &name[len + 1], sizeof(name) - len - 1))
  2019. {
  2020. name[len] = '|';
  2021. }
  2022. }
  2023. if (0 == uiSearchItemAdd(items, name, ot, 0))
  2024. break;
  2025. }
  2026. }
  2027. }
  2028. BLI_ghashIterator_free(iter);
  2029. }
  2030. void uiTemplateOperatorSearch(uiLayout *layout)
  2031. {
  2032. uiBlock *block;
  2033. uiBut *but;
  2034. static char search[256] = "";
  2035. block = uiLayoutGetBlock(layout);
  2036. uiBlockSetCurLayout(block, layout);
  2037. but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
  2038. uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
  2039. }
  2040. /************************* Running Jobs Template **************************/
  2041. #define B_STOPRENDER 1
  2042. #define B_STOPCAST 2
  2043. #define B_STOPANIM 3
  2044. #define B_STOPCOMPO 4
  2045. #define B_STOPSEQ 5
  2046. #define B_STOPCLIP 6
  2047. static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
  2048. {
  2049. switch (event) {
  2050. case B_STOPRENDER:
  2051. G.afbreek = 1;
  2052. break;
  2053. case B_STOPCAST:
  2054. WM_jobs_stop(CTX_wm_manager(C), CTX_wm_screen(C), NULL);
  2055. break;
  2056. case B_STOPANIM:
  2057. WM_operator_name_call(C, "SCREEN_OT_animation_play", WM_OP_INVOKE_SCREEN, NULL);
  2058. break;
  2059. case B_STOPCOMPO:
  2060. WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
  2061. break;
  2062. case B_STOPSEQ:
  2063. WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
  2064. break;
  2065. case B_STOPCLIP:
  2066. WM_jobs_stop(CTX_wm_manager(C), CTX_wm_area(C), NULL);
  2067. break;
  2068. }
  2069. }
  2070. void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
  2071. {
  2072. bScreen *screen = CTX_wm_screen(C);
  2073. wmWindowManager *wm = CTX_wm_manager(C);
  2074. ScrArea *sa = CTX_wm_area(C);
  2075. uiBlock *block;
  2076. void *owner = NULL;
  2077. int handle_event;
  2078. block = uiLayoutGetBlock(layout);
  2079. uiBlockSetCurLayout(block, layout);
  2080. uiBlockSetHandleFunc(block, do_running_jobs, NULL);
  2081. if (sa->spacetype == SPACE_NODE) {
  2082. if (WM_jobs_test(wm, sa))
  2083. owner = sa;
  2084. handle_event = B_STOPCOMPO;
  2085. }
  2086. else if (sa->spacetype == SPACE_SEQ) {
  2087. if (WM_jobs_test(wm, sa))
  2088. owner = sa;
  2089. handle_event = B_STOPSEQ;
  2090. }
  2091. else if (sa->spacetype == SPACE_CLIP) {
  2092. if (WM_jobs_test(wm, sa))
  2093. owner = sa;
  2094. handle_event = B_STOPCLIP;
  2095. }
  2096. else {
  2097. Scene *scene;
  2098. /* another scene can be rendering too, for example via compositor */
  2099. for (scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next)
  2100. if (WM_jobs_test(wm, scene))
  2101. break;
  2102. owner = scene;
  2103. handle_event = B_STOPRENDER;
  2104. }
  2105. if (owner) {
  2106. uiLayout *ui_abs;
  2107. ui_abs = uiLayoutAbsolute(layout, 0);
  2108. (void)ui_abs; // UNUSED
  2109. uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE,
  2110. 0, UI_UNIT_Y * 0.1, UI_UNIT_X * 0.8, UI_UNIT_Y * 0.8, NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop this job"));
  2111. uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner),
  2112. UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, TIP_("Progress"));
  2113. uiLayoutRow(layout, 0);
  2114. }
  2115. if (WM_jobs_test(wm, screen))
  2116. uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0, 0, 85, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
  2117. TIP_("Stop screencast"));
  2118. if (screen->animtimer)
  2119. uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, TIP_("Anim Player"), 0, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0,
  2120. TIP_("Stop animation playback"));
  2121. }
  2122. /************************* Reports for Last Operator Template **************************/
  2123. void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
  2124. {
  2125. ReportList *reports = CTX_wm_reports(C);
  2126. Report *report = BKE_reports_last_displayable(reports);
  2127. ReportTimerInfo *rti;
  2128. uiLayout *ui_abs;
  2129. uiBlock *block;
  2130. uiBut *but;
  2131. uiStyle *style = UI_GetStyle();
  2132. int width;
  2133. int icon = 0;
  2134. /* if the report display has timed out, don't show */
  2135. if (!reports->reporttimer) return;
  2136. rti = (ReportTimerInfo *)reports->reporttimer->customdata;
  2137. if (!rti || rti->widthfac == 0.0f || !report) return;
  2138. ui_abs = uiLayoutAbsolute(layout, 0);
  2139. block = uiLayoutGetBlock(ui_abs);
  2140. width = BLF_width(style->widget.uifont_id, report->message);
  2141. width = MIN2(rti->widthfac * width, width);
  2142. width = MAX2(width, 10);
  2143. /* make a box around the report to make it stand out */
  2144. uiBlockBeginAlign(block);
  2145. but = uiDefBut(block, ROUNDBOX, 0, "", 0, 0, UI_UNIT_X + 10, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
  2146. /* set the report's bg color in but->col - ROUNDBOX feature */
  2147. rgb_float_to_uchar(but->col, rti->col);
  2148. but->col[3] = 255;
  2149. but = uiDefBut(block, ROUNDBOX, 0, "", UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
  2150. but->col[0] = but->col[1] = but->col[2] = FTOCHAR(rti->greyscale);
  2151. but->col[3] = 255;
  2152. uiBlockEndAlign(block);
  2153. /* icon and report message on top */
  2154. if (report->type & RPT_ERROR_ALL)
  2155. icon = ICON_ERROR;
  2156. else if (report->type & RPT_WARNING_ALL)
  2157. icon = ICON_ERROR;
  2158. else if (report->type & RPT_INFO_ALL)
  2159. icon = ICON_INFO;
  2160. /* XXX: temporary operator to dump all reports to a text block, but only if more than 1 report
  2161. * to be shown instead of icon when appropriate...
  2162. */
  2163. uiBlockSetEmboss(block, UI_EMBOSSN);
  2164. if (reports->list.first != reports->list.last)
  2165. uiDefIconButO(block, BUT, "UI_OT_reports_to_textblock", WM_OP_INVOKE_REGION_WIN, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, TIP_("Click to see rest of reports in textblock: 'Recent Reports'"));
  2166. else
  2167. uiDefIconBut(block, LABEL, 0, icon, 2, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
  2168. uiBlockSetEmboss(block, UI_EMBOSS);
  2169. uiDefBut(block, LABEL, 0, report->message, UI_UNIT_X + 10, 0, UI_UNIT_X + width, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "");
  2170. }
  2171. /********************************* Keymap *************************************/
  2172. static void keymap_item_modified(bContext *UNUSED(C), void *kmi_p, void *UNUSED(unused))
  2173. {
  2174. wmKeyMapItem *kmi = (wmKeyMapItem *)kmi_p;
  2175. WM_keyconfig_update_tag(NULL, kmi);
  2176. }
  2177. static void template_keymap_item_properties(uiLayout *layout, const char *title, PointerRNA *ptr)
  2178. {
  2179. uiLayout *flow;
  2180. uiItemS(layout);
  2181. if (title)
  2182. uiItemL(layout, title, ICON_NONE);
  2183. flow = uiLayoutColumnFlow(layout, 2, 0);
  2184. RNA_STRUCT_BEGIN(ptr, prop) {
  2185. int flag = RNA_property_flag(prop);
  2186. if (flag & PROP_HIDDEN)
  2187. continue;
  2188. /* recurse for nested properties */
  2189. if (RNA_property_type(prop) == PROP_POINTER) {
  2190. PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
  2191. const char *name = RNA_property_ui_name(prop);
  2192. if (propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
  2193. template_keymap_item_properties(layout, name, &propptr);
  2194. continue;
  2195. }
  2196. }
  2197. /* add property */
  2198. uiItemR(flow, ptr, RNA_property_identifier(prop), 0, NULL, ICON_NONE);
  2199. }
  2200. RNA_STRUCT_END;
  2201. }
  2202. void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
  2203. {
  2204. PointerRNA propptr = RNA_pointer_get(ptr, "properties");
  2205. if (propptr.data) {
  2206. uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
  2207. template_keymap_item_properties(layout, NULL, &propptr);
  2208. /* attach callbacks to compensate for missing properties update,
  2209. * we don't know which keymap (item) is being modified there */
  2210. for (; but; but = but->next)
  2211. uiButSetFunc(but, keymap_item_modified, ptr->data, NULL);
  2212. }
  2213. }