PageRenderTime 73ms CodeModel.GetById 29ms 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

Large files files are truncated, but you can click here to view the full file

  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->

Large files files are truncated, but you can click here to view the full file