2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2004 Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): Joshua Leung
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/space_outliner/outliner_draw.c
32 #include "DNA_anim_types.h"
33 #include "DNA_armature_types.h"
34 #include "DNA_gpencil_types.h"
35 #include "DNA_group_types.h"
36 #include "DNA_lamp_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_sequence_types.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_string_utils.h"
44 #include "BLI_utildefines.h"
45 #include "BLI_mempool.h"
47 #include "BLT_translation.h"
49 #include "BKE_context.h"
50 #include "BKE_deform.h"
51 #include "BKE_fcurve.h"
52 #include "BKE_global.h"
53 #include "BKE_layer.h"
54 #include "BKE_library.h"
56 #include "BKE_modifier.h"
57 #include "BKE_report.h"
58 #include "BKE_scene.h"
59 #include "BKE_object.h"
61 #include "DEG_depsgraph.h"
63 #include "ED_armature.h"
64 #include "ED_keyframing.h"
65 #include "ED_object.h"
66 #include "ED_screen.h"
71 #include "GPU_immediate.h"
73 #include "UI_interface.h"
74 #include "UI_interface_icons.h"
75 #include "UI_resources.h"
76 #include "UI_view2d.h"
78 #include "RNA_access.h"
80 #include "outliner_intern.h"
82 /* disable - this is far too slow - campbell */
83 // #define USE_GROUP_SELECT
85 /* ****************************************************** */
86 /* Tree Size Functions */
88 static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
90 TreeElement *te = lb->first;
92 TreeStoreElem *tselem = TREESTORE(te);
93 if (TSELEM_OPEN(tselem, soops))
94 outliner_height(soops, &te->subtree, h);
100 #if 0 // XXX this is currently disabled until te->xend is set correctly
101 static void outliner_width(SpaceOops *soops, ListBase *lb, int *w)
103 TreeElement *te = lb->first;
105 // TreeStoreElem *tselem = TREESTORE(te);
107 // XXX fixme... te->xend is not set yet
108 if (!TSELEM_OPEN(tselem, soops)) {
112 outliner_width(soops, &te->subtree, w);
118 static void outliner_rna_width(SpaceOops *soops, ListBase *lb, int *w, int startx)
120 TreeElement *te = lb->first;
122 TreeStoreElem *tselem = TREESTORE(te);
123 // XXX fixme... (currently, we're using a fixed length of 100)!
130 if (startx + 100 > *w)
133 if (TSELEM_OPEN(tselem, soops))
134 outliner_rna_width(soops, &te->subtree, w, startx + UI_UNIT_X);
139 /* ****************************************************** */
141 static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent, int flag, bool set_flag)
143 Object *obedit = CTX_data_edit_object(C);
144 bArmature *arm = obedit->data;
147 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
148 if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) {
150 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
154 ebone->flag &= ~flag;
160 static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag)
163 for (bone = bone_parent->childbase.first; bone; bone = bone->next) {
165 bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
171 restrictbutton_recursive_bone(bone, flag, set_flag);
176 static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2))
178 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin);
181 static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *poin2)
183 Object *ob = (Object *)poin2;
185 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
186 WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
189 static void restrictbutton_bone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
191 Bone *bone = (Bone *)poin2;
192 if (bone->flag & BONE_HIDDEN_P)
193 bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
195 if (CTX_wm_window(C)->eventstate->ctrl) {
196 restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
199 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
202 static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
204 Bone *bone = (Bone *)poin2;
205 if (bone->flag & BONE_UNSELECTABLE)
206 bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
208 if (CTX_wm_window(C)->eventstate->ctrl) {
209 restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
212 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
215 static void restrictbutton_ebone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
217 EditBone *ebone = (EditBone *)poin2;
219 if (ebone->flag & BONE_UNSELECTABLE) {
220 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
223 if (CTX_wm_window(C)->eventstate->ctrl) {
224 restrictbutton_recursive_ebone(C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
227 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
230 static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2)
232 EditBone *ebone = (EditBone *)poin2;
233 if (ebone->flag & BONE_HIDDEN_A) {
234 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
237 if (CTX_wm_window(C)->eventstate->ctrl) {
238 restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
241 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
244 static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), void *UNUSED(poin2))
246 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
249 static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2))
252 /* hide and deselect bases that are directly influenced by this LayerCollection */
253 /* TODO(sergey): Use proper flag for tagging here. */
254 DEG_id_tag_update(&scene->id, 0);
255 WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
256 WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
259 static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
263 BLI_assert(id != NULL);
265 if (id->flag & LIB_FAKEUSER) {
274 static void namebutton_cb(bContext *C, void *tsep, char *oldname)
276 SpaceOops *soops = CTX_wm_space_outliner(C);
277 Scene *scene = CTX_data_scene(C);
278 SceneLayer *sl = CTX_data_scene_layer(C);
279 Object *obedit = CTX_data_edit_object(C);
280 BLI_mempool *ts = soops->treestore;
281 TreeStoreElem *tselem = tsep;
284 TreeElement *te = outliner_find_tree_element(&soops->tree, tselem);
286 if (tselem->type == 0) {
287 BLI_libblock_ensure_unique_name(G.main, tselem->id->name);
289 switch (GS(tselem->id->name)) {
291 WM_event_add_notifier(C, NC_MATERIAL, NULL); break;
293 WM_event_add_notifier(C, NC_TEXTURE, NULL); break;
295 WM_event_add_notifier(C, NC_IMAGE, NULL); break;
297 WM_event_add_notifier(C, NC_SCENE, NULL); break;
299 WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break;
301 /* Check the library target exists */
302 if (te->idcode == ID_LI) {
303 Library *lib = (Library *)tselem->id;
304 char expanded[FILE_MAX];
306 BKE_library_filepath_set(lib, lib->name);
308 BLI_strncpy(expanded, lib->name, sizeof(expanded));
309 BLI_path_abs(expanded, G.main->name);
310 if (!BLI_exists(expanded)) {
311 BKE_reportf(CTX_wm_reports(C), RPT_ERROR,
312 "Library path '%s' does not exist, correct this before saving", expanded);
314 else if (lib->id.tag & LIB_TAG_MISSING) {
315 BKE_reportf(CTX_wm_reports(C), RPT_INFO,
316 "Library path '%s' is now valid, please reload the library", expanded);
317 lib->id.tag &= ~LIB_TAG_MISSING;
322 switch (tselem->type) {
324 defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object
327 BLI_libblock_ensure_unique_name(G.main, tselem->id->name);
331 bArmature *arm = (bArmature *)tselem->id;
333 EditBone *ebone = te->directdata;
334 char newname[sizeof(ebone->name)];
336 /* restore bone name */
337 BLI_strncpy(newname, ebone->name, sizeof(ebone->name));
338 BLI_strncpy(ebone->name, oldname, sizeof(ebone->name));
339 ED_armature_bone_rename(obedit->data, oldname, newname);
340 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, OBACT_NEW(sl));
347 Bone *bone = te->directdata;
349 char newname[sizeof(bone->name)];
351 /* always make current object active */
352 tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, true);
355 /* restore bone name */
356 BLI_strncpy(newname, bone->name, sizeof(bone->name));
357 BLI_strncpy(bone->name, oldname, sizeof(bone->name));
358 ED_armature_bone_rename(ob->data, oldname, newname);
359 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
362 case TSE_POSE_CHANNEL:
364 bPoseChannel *pchan = te->directdata;
366 char newname[sizeof(pchan->name)];
368 /* always make current pose-bone active */
369 tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NORMAL, true);
372 BLI_assert(ob->type == OB_ARMATURE);
374 /* restore bone name */
375 BLI_strncpy(newname, pchan->name, sizeof(pchan->name));
376 BLI_strncpy(pchan->name, oldname, sizeof(pchan->name));
377 ED_armature_bone_rename(ob->data, oldname, newname);
378 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
383 Object *ob = (Object *)tselem->id; // id = object
384 bActionGroup *grp = te->directdata;
386 BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), '.',
387 offsetof(bActionGroup, name), sizeof(grp->name));
388 WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
393 bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock
394 bGPDlayer *gpl = te->directdata;
396 // XXX: name needs translation stuff
397 BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.',
398 offsetof(bGPDlayer, info), sizeof(gpl->info));
399 WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd);
404 case TSE_SCENE_COLLECTION:
405 case TSE_LAYER_COLLECTION:
407 SceneCollection *sc = outliner_scene_collection_from_tree_element(te);
408 BKE_collection_rename(scene, sc, te->name);
413 tselem->flag &= ~TSE_TEXTBUT;
417 static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops, ListBase *lb)
421 TreeStoreElem *tselem;
424 PropertyRNA *object_prop_hide, *object_prop_hide_select, *object_prop_hide_render;
426 /* get RNA properties (once) */
427 object_prop_hide = RNA_struct_type_find_property(&RNA_Object, "hide");
428 object_prop_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select");
429 object_prop_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render");
430 BLI_assert(object_prop_hide && object_prop_hide_select && object_prop_hide_render);
433 for (te = lb->first; te; te = te->next) {
434 tselem = TREESTORE(te);
435 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
436 /* scene render layers and passes have toggle-able flags too! */
437 if (tselem->type == TSE_R_LAYER) {
438 UI_block_emboss_set(block, UI_EMBOSS_NONE);
440 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
441 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
442 UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer"));
443 UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
444 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
446 UI_block_emboss_set(block, UI_EMBOSS);
448 else if (tselem->type == TSE_R_PASS) {
449 int *layflag = te->directdata;
450 int passflag = 1 << tselem->nr;
452 UI_block_emboss_set(block, UI_EMBOSS_NONE);
455 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, passflag, 0, ICON_CHECKBOX_HLT - 1,
456 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
457 UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass"));
458 UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
459 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
461 layflag++; /* is lay_xor */
462 if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
463 SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
465 bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
466 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
467 UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined"));
468 UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
469 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
472 UI_block_emboss_set(block, UI_EMBOSS);
474 else if (tselem->type == TSE_MODIFIER) {
475 ModifierData *md = (ModifierData *)te->directdata;
476 ob = (Object *)tselem->id;
478 UI_block_emboss_set(block, UI_EMBOSS_NONE);
479 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
480 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
481 UI_UNIT_Y, &(md->mode), 0, 0, 0, 0,
482 TIP_("Restrict/Allow visibility in the 3D View"));
483 UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
484 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
486 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
487 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
488 UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
489 UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
490 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
492 UI_block_emboss_set(block, UI_EMBOSS);
494 else if (tselem->type == TSE_POSE_CHANNEL) {
495 bPoseChannel *pchan = (bPoseChannel *)te->directdata;
496 Bone *bone = pchan->bone;
497 ob = (Object *)tselem->id;
499 UI_block_emboss_set(block, UI_EMBOSS_NONE);
500 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
501 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
502 UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
503 TIP_("Restrict/Allow visibility in the 3D View"));
504 UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
505 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
507 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
508 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
509 UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
510 TIP_("Restrict/Allow selection in the 3D View"));
511 UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone);
512 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
514 UI_block_emboss_set(block, UI_EMBOSS);
516 else if (tselem->type == TSE_EBONE) {
517 EditBone *ebone = (EditBone *)te->directdata;
519 UI_block_emboss_set(block, UI_EMBOSS_NONE);
520 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
521 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
522 UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
523 TIP_("Restrict/Allow visibility in the 3D View"));
524 UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
525 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
527 bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
528 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
529 UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
530 TIP_("Restrict/Allow selection in the 3D View"));
531 UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone);
532 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
534 UI_block_emboss_set(block, UI_EMBOSS);
536 else if (tselem->type == TSE_GP_LAYER) {
537 bGPDlayer *gpl = (bGPDlayer *)te->directdata;
539 UI_block_emboss_set(block, UI_EMBOSS_NONE);
541 bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_RESTRICT_VIEW_OFF,
542 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
543 UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
544 TIP_("Restrict/Allow visibility in the 3D View"));
545 UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
546 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
548 bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED,
549 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
550 UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
551 TIP_("Restrict/Allow editing of strokes and keyframes in this layer"));
552 UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
553 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
555 /* TODO: visibility in renders */
557 UI_block_emboss_set(block, UI_EMBOSS);
559 else if (tselem->type == TSE_LAYER_COLLECTION) {
560 LayerCollection *collection = te->directdata;
562 UI_block_emboss_set(block, UI_EMBOSS_NONE);
564 bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF,
565 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
566 UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
567 TIP_("Restrict/Allow 3D View visibility of objects in the collection"));
568 UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
569 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
571 bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
572 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
573 UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
574 TIP_("Restrict/Allow 3D View selection of objects in the collection"));
575 UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
576 UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
578 UI_block_emboss_set(block, UI_EMBOSS);
582 if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
586 static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb)
590 TreeStoreElem *tselem;
592 for (te = lb->first; te; te = te->next) {
593 tselem = TREESTORE(te);
594 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
595 if (tselem->type == 0) {
597 const char *tip = NULL;
598 int icon = ICON_NONE;
600 int but_flag = UI_BUT_DRAG_LOCK;
602 if (ID_IS_LINKED_DATABLOCK(id))
603 but_flag |= UI_BUT_DISABLED;
605 UI_block_emboss_set(block, UI_EMBOSS_NONE);
607 if (id->flag & LIB_FAKEUSER) {
608 icon = ICON_FILE_TICK;
609 tip = TIP_("Data-block will be retained using a fake user");
613 tip = TIP_("Data-block has no users and will be deleted");
615 bt = uiDefIconButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon,
616 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
617 &id->flag, 0, 0, 0, 0, tip);
618 UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
619 UI_but_flag_enable(bt, but_flag);
622 BLI_str_format_int_grouped(buf, id->us);
623 bt = uiDefBut(block, UI_BTYPE_BUT, 1, buf,
624 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys,
625 UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0,
626 TIP_("Number of users of this data-block"));
627 UI_but_flag_enable(bt, but_flag);
630 bt = uiDefButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ",
631 (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
632 &id->flag, 0, 0, 0, 0,
633 TIP_("Data-block has a 'fake' user which will keep it in the file "
634 "even if nothing else uses it"));
635 UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
636 UI_but_flag_enable(bt, but_flag);
638 UI_block_emboss_set(block, UI_EMBOSS);
642 if (TSELEM_OPEN(tselem, soops)) outliner_draw_userbuts(block, ar, soops, &te->subtree);
646 static void outliner_draw_rnacols(ARegion *ar, int sizex)
648 View2D *v2d = &ar->v2d;
650 float miny = v2d->cur.ymin;
651 if (miny < v2d->tot.ymin) miny = v2d->tot.ymin;
655 unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
656 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
657 immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
659 immBegin(GWN_PRIM_LINES, 4);
661 immVertex2f(pos, sizex, v2d->cur.ymax);
662 immVertex2f(pos, sizex, miny);
664 immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, v2d->cur.ymax);
665 immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, miny);
672 static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOops *soops, int sizex, ListBase *lb)
675 TreeStoreElem *tselem;
679 for (te = lb->first; te; te = te->next) {
680 tselem = TREESTORE(te);
681 if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
682 if (tselem->type == TSE_RNA_PROPERTY) {
684 prop = te->directdata;
686 if (!TSELEM_OPEN(tselem, soops)) {
687 if (RNA_property_type(prop) == PROP_POINTER) {
688 uiBut *but = uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys,
689 OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
690 UI_but_flag_enable(but, UI_BUT_DISABLED);
692 else if (RNA_property_type(prop) == PROP_ENUM) {
693 uiDefAutoButR(block, ptr, prop, -1, NULL, ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
697 uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
702 else if (tselem->type == TSE_RNA_ARRAY_ELEM) {
704 prop = te->directdata;
706 uiDefAutoButR(block, ptr, prop, te->index, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
711 if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, ar, soops, sizex, &te->subtree);
714 UI_block_emboss_set(block, UI_EMBOSS);
717 static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te)
720 TreeStoreElem *tselem;
723 tselem = TREESTORE(te);
725 BLI_assert(tselem->flag & TSE_TEXTBUT);
726 /* If we add support to rename Sequence.
730 if (tselem->type == TSE_EBONE) len = sizeof(((EditBone *) 0)->name);
731 else if (tselem->type == TSE_MODIFIER) len = sizeof(((ModifierData *) 0)->name);
732 else if (tselem->id && GS(tselem->id->name) == ID_LI) len = sizeof(((Library *) 0)->name);
733 else len = MAX_ID_NAME - 2;
735 spx = te->xs + 1.8f * UI_UNIT_X;
736 dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X);
738 bt = uiDefBut(block, UI_BTYPE_TEXT, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
739 1.0, (float)len, 0, 0, "");
740 UI_but_func_rename_set(bt, namebutton_cb, tselem);
742 /* returns false if button got removed */
743 if (false == UI_but_active_only(C, ar, block, bt)) {
744 tselem->flag &= ~TSE_TEXTBUT;
746 /* bad! (notifier within draw) without this, we don't get a refesh */
747 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
751 /* ****************************************************** */
752 /* Normal Drawing... */
754 /* make function calls a bit compacter */
758 float xmax, x, y, xb, yb;
762 static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
764 /* restrict column clip... it has been coded by simply overdrawing, doesnt work for buttons */
765 if (arg->x >= arg->xmax) {
767 UI_icon_draw_alpha(arg->x, arg->y, icon, arg->alpha);
771 uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
772 0.0, 0.0, 1.0, arg->alpha,
773 (arg->id && ID_IS_LINKED_DATABLOCK(arg->id)) ? arg->id->lib->name : "");
776 UI_but_drag_set_id(but, arg->id);
781 static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
783 /* restrict column clip - skip it for now... */
784 if (arg->x >= arg->xmax) {
789 const float eps = 0.001f;
790 const bool is_stroke_visible = (gpl->color[3] > eps);
791 const bool is_fill_visible = (gpl->fill[3] > eps);
792 float w = 0.5f * UI_UNIT_X;
793 float h = 0.85f * UI_UNIT_Y;
795 RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr);
797 UI_block_align_begin(arg->block);
799 UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
800 uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
804 UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
805 uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h,
806 &ptr, "fill_color", -1,
809 UI_block_emboss_set(arg->block, UI_EMBOSS_NONE);
810 UI_block_align_end(arg->block);
814 static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
817 struct DrawIconArg arg;
820 /* make function calls a bit compacter */
824 arg.xb = x; /* for ui buttons */
828 /* placement of icons, copied from interface_widgets.c */
829 aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
835 #define ICON_DRAW(_icon) UI_icon_draw_alpha(x, y, _icon, alpha)
838 switch (tselem->type) {
840 ICON_DRAW(ICON_ANIM_DATA); /* XXX */
846 ICON_DRAW(ICON_NLA); /* XXX */
849 ICON_DRAW(ICON_ACTION);
851 case TSE_DRIVER_BASE:
852 ICON_DRAW(ICON_DRIVER);
854 case TSE_DEFGROUP_BASE:
855 ICON_DRAW(ICON_GROUP_VERTEX);
859 ICON_DRAW(ICON_BONE_DATA);
861 case TSE_CONSTRAINT_BASE:
862 ICON_DRAW(ICON_CONSTRAINT);
864 case TSE_MODIFIER_BASE:
865 ICON_DRAW(ICON_MODIFIER);
868 ICON_DRAW(ICON_OBJECT_DATA);
870 case TSE_LINKED_PSYS:
871 ICON_DRAW(ICON_PARTICLES);
875 Object *ob = (Object *)tselem->id;
876 ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
877 switch ((ModifierType)md->type) {
878 case eModifierType_Subsurf:
879 ICON_DRAW(ICON_MOD_SUBSURF);
881 case eModifierType_Armature:
882 ICON_DRAW(ICON_MOD_ARMATURE);
884 case eModifierType_Lattice:
885 ICON_DRAW(ICON_MOD_LATTICE);
887 case eModifierType_Curve:
888 ICON_DRAW(ICON_MOD_CURVE);
890 case eModifierType_Build:
891 ICON_DRAW(ICON_MOD_BUILD);
893 case eModifierType_Mirror:
894 ICON_DRAW(ICON_MOD_MIRROR);
896 case eModifierType_Decimate:
897 ICON_DRAW(ICON_MOD_DECIM);
899 case eModifierType_Wave:
900 ICON_DRAW(ICON_MOD_WAVE);
902 case eModifierType_Hook:
903 ICON_DRAW(ICON_HOOK);
905 case eModifierType_Softbody:
906 ICON_DRAW(ICON_MOD_SOFT);
908 case eModifierType_Boolean:
909 ICON_DRAW(ICON_MOD_BOOLEAN);
911 case eModifierType_ParticleSystem:
912 ICON_DRAW(ICON_MOD_PARTICLES);
914 case eModifierType_ParticleInstance:
915 ICON_DRAW(ICON_MOD_PARTICLES);
917 case eModifierType_EdgeSplit:
918 ICON_DRAW(ICON_MOD_EDGESPLIT);
920 case eModifierType_Array:
921 ICON_DRAW(ICON_MOD_ARRAY);
923 case eModifierType_UVProject:
924 case eModifierType_UVWarp: /* TODO, get own icon */
925 ICON_DRAW(ICON_MOD_UVPROJECT);
927 case eModifierType_Displace:
928 ICON_DRAW(ICON_MOD_DISPLACE);
930 case eModifierType_Shrinkwrap:
931 ICON_DRAW(ICON_MOD_SHRINKWRAP);
933 case eModifierType_Cast:
934 ICON_DRAW(ICON_MOD_CAST);
936 case eModifierType_MeshDeform:
937 case eModifierType_SurfaceDeform:
938 ICON_DRAW(ICON_MOD_MESHDEFORM);
940 case eModifierType_Bevel:
941 ICON_DRAW(ICON_MOD_BEVEL);
943 case eModifierType_Smooth:
944 case eModifierType_LaplacianSmooth:
945 case eModifierType_CorrectiveSmooth:
946 ICON_DRAW(ICON_MOD_SMOOTH);
948 case eModifierType_SimpleDeform:
949 ICON_DRAW(ICON_MOD_SIMPLEDEFORM);
951 case eModifierType_Mask:
952 ICON_DRAW(ICON_MOD_MASK);
954 case eModifierType_Cloth:
955 ICON_DRAW(ICON_MOD_CLOTH);
957 case eModifierType_Explode:
958 ICON_DRAW(ICON_MOD_EXPLODE);
960 case eModifierType_Collision:
961 case eModifierType_Surface:
962 ICON_DRAW(ICON_MOD_PHYSICS);
964 case eModifierType_Fluidsim:
965 ICON_DRAW(ICON_MOD_FLUIDSIM);
967 case eModifierType_Multires:
968 ICON_DRAW(ICON_MOD_MULTIRES);
970 case eModifierType_Smoke:
971 ICON_DRAW(ICON_MOD_SMOKE);
973 case eModifierType_Solidify:
974 ICON_DRAW(ICON_MOD_SOLIDIFY);
976 case eModifierType_Screw:
977 ICON_DRAW(ICON_MOD_SCREW);
979 case eModifierType_Remesh:
980 ICON_DRAW(ICON_MOD_REMESH);
982 case eModifierType_WeightVGEdit:
983 case eModifierType_WeightVGMix:
984 case eModifierType_WeightVGProximity:
985 ICON_DRAW(ICON_MOD_VERTEX_WEIGHT);
987 case eModifierType_DynamicPaint:
988 ICON_DRAW(ICON_MOD_DYNAMICPAINT);
990 case eModifierType_Ocean:
991 ICON_DRAW(ICON_MOD_OCEAN);
993 case eModifierType_Warp:
994 ICON_DRAW(ICON_MOD_WARP);
996 case eModifierType_Skin:
997 ICON_DRAW(ICON_MOD_SKIN);
999 case eModifierType_Triangulate:
1000 ICON_DRAW(ICON_MOD_TRIANGULATE);
1002 case eModifierType_MeshCache:
1003 ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
1005 case eModifierType_MeshSequenceCache:
1006 ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
1008 case eModifierType_Wireframe:
1009 ICON_DRAW(ICON_MOD_WIREFRAME);
1011 case eModifierType_LaplacianDeform:
1012 ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
1014 case eModifierType_DataTransfer:
1015 ICON_DRAW(ICON_MOD_DATA_TRANSFER);
1017 case eModifierType_NormalEdit:
1018 ICON_DRAW(ICON_MOD_NORMALEDIT);
1021 case eModifierType_None:
1022 case eModifierType_ShapeKey:
1023 case NUM_MODIFIER_TYPES:
1024 ICON_DRAW(ICON_DOT);
1030 ICON_DRAW(ICON_ARMATURE_DATA);
1032 case TSE_POSE_CHANNEL:
1033 ICON_DRAW(ICON_BONE_DATA);
1036 ICON_DRAW(ICON_GHOST);
1038 case TSE_R_LAYER_BASE:
1039 ICON_DRAW(ICON_RENDERLAYERS);
1042 ICON_DRAW(ICON_RENDERLAYERS);
1044 case TSE_LINKED_LAMP:
1045 ICON_DRAW(ICON_LAMP_DATA);
1047 case TSE_LINKED_MAT:
1048 ICON_DRAW(ICON_MATERIAL_DATA);
1050 case TSE_POSEGRP_BASE:
1051 ICON_DRAW(ICON_GROUP_BONE);
1054 if (te->idcode == SEQ_TYPE_MOVIE)
1055 ICON_DRAW(ICON_SEQUENCE);
1056 else if (te->idcode == SEQ_TYPE_META)
1057 ICON_DRAW(ICON_DOT);
1058 else if (te->idcode == SEQ_TYPE_SCENE)
1059 ICON_DRAW(ICON_SCENE);
1060 else if (te->idcode == SEQ_TYPE_SOUND_RAM)
1061 ICON_DRAW(ICON_SOUND);
1062 else if (te->idcode == SEQ_TYPE_IMAGE)
1063 ICON_DRAW(ICON_IMAGE_COL);
1065 ICON_DRAW(ICON_PARTICLES);
1068 ICON_DRAW(ICON_LIBRARY_DATA_DIRECT);
1070 case TSE_SEQUENCE_DUP:
1071 ICON_DRAW(ICON_OBJECT_DATA);
1073 case TSE_RNA_STRUCT:
1074 if (RNA_struct_is_ID(te->rnaptr.type)) {
1075 arg.id = (ID *)te->rnaptr.data;
1076 tselem_draw_icon_uibut(&arg, RNA_struct_ui_icon(te->rnaptr.type));
1079 int icon = RNA_struct_ui_icon(te->rnaptr.type);
1083 /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */
1086 tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
1090 ICON_DRAW(ICON_DOT);
1094 else if (tselem->id) {
1095 if (GS(tselem->id->name) == ID_OB) {
1096 Object *ob = (Object *)tselem->id;
1099 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break;
1101 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break;
1103 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break;
1105 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break;
1107 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break;
1109 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break;
1111 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break;
1113 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break;
1115 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break;
1117 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break;
1119 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break;
1123 /* TODO(sergey): Casting to short here just to handle ID_NLA which is
1124 * NOT inside of IDType enum.
1126 switch ((short)GS(tselem->id->name)) {
1128 tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break;
1130 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break;
1132 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break;
1134 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break;
1136 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break;
1139 Lamp *la = (Lamp *)tselem->id;
1142 tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break;
1144 tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break;
1146 tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break;
1148 tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break;
1150 tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break;
1152 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break;
1157 tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break;
1159 tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break;
1161 tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break;
1164 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break;
1166 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break;
1168 tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break;
1170 tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break;
1172 tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break;
1174 tselem_draw_icon_uibut(&arg, ICON_ACTION); break;
1176 tselem_draw_icon_uibut(&arg, ICON_NLA); break;
1178 tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break;
1180 tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
1182 if (tselem->id->tag & LIB_TAG_MISSING) {
1183 tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN);
1185 else if (((Library *)tselem->id)->parent) {
1186 tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT);
1189 tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT);
1193 tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
1195 tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
1205 static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, SceneLayer *sl, SpaceOops *soops,
1206 ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac)
1209 TreeStoreElem *tselem;
1210 eOLDrawState active;
1212 for (te = lb->first; te; te = te->next) {
1213 /* exit drawing early */
1214 if ((*offsx) - UI_UNIT_X > xmax)
1217 tselem = TREESTORE(te);
1219 /* object hierarchy always, further constrained on level */
1220 if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) {
1222 /* active blocks get white circle */
1223 if (tselem->type == 0) {
1224 if (te->idcode == ID_OB) {
1225 active = (OBACT_NEW(sl) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
1227 else if (scene->obedit && scene->obedit->data == tselem->id) {
1228 active = OL_DRAWSEL_NORMAL;
1231 active = tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NONE, false);
1235 active = tree_element_type_active(C, scene, sl, soops, te, tselem, OL_SETSEL_NONE, false);
1238 if (active != OL_DRAWSEL_NONE) {
1239 float ufac = UI_UNIT_X / 20.0f;
1240 float color[4] = {1.0f, 1.0f, 1.0f, 0.4f};
1242 UI_draw_roundbox_corner_set(UI_CNR_ALL);
1243 color[3] *= alpha_fac;
1245 UI_draw_roundbox_aa(
1247 (float) *offsx + 1.0f * ufac,
1248 (float)ys + 1.0f * ufac,
1249 (float)*offsx + UI_UNIT_X - 1.0f * ufac,
1250 (float)ys + UI_UNIT_Y - ufac,
1251 (float)UI_UNIT_Y / 2.0f - ufac,
1253 glEnable(GL_BLEND); /* roundbox disables */
1256 tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac);
1259 te->xend = (short)*offsx + UI_UNIT_X;
1260 te->flag |= TE_ICONROW; // for click
1262 (*offsx) += UI_UNIT_X;
1265 /* this tree element always has same amount of branches, so don't draw */
1266 if (tselem->type != TSE_R_LAYER)
1267 outliner_draw_iconrow(C, block, scene, sl, soops, &te->subtree, level + 1, xmax, offsx, ys, alpha_fac);
1272 /* closed tree element */
1273 static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty)
1277 /* closed items may be displayed in row of parent, don't change their coordinate! */
1278 if ((te->flag & TE_ICONROW) == 0) {
1279 /* store coord and continue, we need coordinates for elements outside view too */
1284 for (ten = te->subtree.first; ten; ten = ten->next) {
1285 outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
1290 static void outliner_draw_tree_element(
1291 bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, SceneLayer *sl,
1292 ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out,
1293 int startx, int *starty, TreeElement **te_edit, TreeElement **te_floating)
1295 TreeStoreElem *tselem;
1296 float ufac = UI_UNIT_X / 20.0f;
1298 eOLDrawState active = OL_DRAWSEL_NONE;
1300 tselem = TREESTORE(te);
1302 if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) {
1303 const float alpha_fac = draw_grayed_out ? 0.5f : 1.0f;
1304 const float alpha = 0.5f * alpha_fac;
1305 int xmax = ar->v2d.cur.xmax;
1307 if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) {
1310 if ((te->drag_data != NULL) && (*te_floating == NULL)) {
1314 /* icons can be ui buts, we don't want it to overlap with restrict */
1315 if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
1316 xmax -= OL_TOGW + UI_UNIT_X;
1320 /* colors for active/selected data */
1321 if (tselem->type == 0) {
1322 if (te->idcode == ID_SCE) {
1323 if (tselem->id == (ID *)scene) {
1324 rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha);
1325 active = OL_DRAWSEL_ACTIVE;
1328 else if (te->idcode == ID_OB) {
1329 Object *ob = (Object *)tselem->id;
1331 if (ob == OBACT_NEW(sl) || (ob->flag & SELECT)) {
1332 char col[4] = {0, 0, 0, 0};
1334 /* outliner active ob: always white text, circle color now similar to view3d */
1336 active = OL_DRAWSEL_ACTIVE;
1337 if (ob == OBACT_NEW(sl)) {
1338 if (ob->flag & SELECT) {
1339 UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
1343 active = OL_DRAWSEL_NORMAL;
1345 else if (ob->flag & SELECT) {
1346 UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
1349 rgba_float_args_set(color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha);
1353 else if (scene->obedit && scene->obedit->data == tselem->id) {
1354 rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha);
1355 active = OL_DRAWSEL_ACTIVE;
1358 if (tree_element_active(C, scene, sl, soops, te, OL_SETSEL_NONE, false)) {
1359 rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha);
1360 active = OL_DRAWSEL_ACTIVE;
1365 active = tree_element_type_active(C, scene, sl, soops, te, tselem, OL_SETSEL_NONE, false);
1366 rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha);
1370 if (active != OL_DRAWSEL_NONE) {
1371 UI_draw_roundbox_corner_set(UI_CNR_ALL);
1372 UI_draw_roundbox_aa(
1374 (float)startx + UI_UNIT_X + 1.0f * ufac,
1375 (float)*starty + 1.0f * ufac,
1376 (float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac,
1377 (float)*starty + UI_UNIT_Y - 1.0f * ufac,
1378 UI_UNIT_Y / 2.0f - 1.0f * ufac, color);
1379 glEnable(GL_BLEND); /* roundbox disables it */
1381 te->flag |= TE_ACTIVE; // for lookup in display hierarchies
1384 /* open/close icon, only when sublevels, except for scene */
1385 if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) {
1387 if (tselem->type == 0 && ELEM(te->idcode, ID_OB, ID_SCE))
1390 icon_x = startx + 5 * ufac;
1392 // icons a bit higher
1393 if (TSELEM_OPEN(tselem, soops))
1394 UI_icon_draw_alpha((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_DOWN,
1397 UI_icon_draw_alpha((float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_RIGHT,
1404 if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM))) {
1405 tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac);
1406 offsx += UI_UNIT_X + 2 * ufac;
1411 if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
1412 if (tselem->id->tag & LIB_TAG_MISSING) {
1413 UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN,
1416 else if (tselem->id->tag & LIB_TAG_INDIRECT) {
1417 UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT,
1421 UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT,
1424 offsx += UI_UNIT_X + 2 * ufac;
1426 glDisable(GL_BLEND);
1429 if ((tselem->flag & TSE_TEXTBUT) == 0) {
1430 unsigned char text_col[4];
1432 if (active == OL_DRAWSEL_NORMAL) {
1433 UI_GetThemeColor4ubv(TH_TEXT_HI, text_col);
1435 else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
1436 UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col);
1440 UI_GetThemeColor4ubv(TH_TEXT, text_col);
1442 text_col[3] *= alpha_fac;
1444 UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col);
1447 offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
1449 /* closed item, we draw the icons, not when it's a scene, or master-server list though */
1450 if (!TSELEM_OPEN(tselem, soops)) {
1451 if (te->subtree.first) {
1452 if (tselem->type == 0 && te->idcode == ID_SCE) {
1455 /* this tree element always has same amount of branches, so don't draw */
1456 else if (tselem->type != TSE_R_LAYER) {
1457 int tempx = startx + offsx;
1463 Gwn_VertFormat *format = immVertexFormat();
1464 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
1465 unsigned char col[4];
1467 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1468 UI_GetThemeColorShade4ubv(TH_BACK, -40, col);
1469 col[3] *= alpha_fac;
1471 immUniformColor4ubv(col);
1472 immRecti(pos, tempx - 10.0f * ufac,
1473 *starty + 4.0f * ufac,
1474 tempx - 8.0f * ufac,
1475 *starty + UI_UNIT_Y - 4.0f * ufac);
1479 outliner_draw_iconrow(C, block, scene, sl, soops, &te->subtree, 0, xmax, &tempx,
1480 *starty, alpha_fac);
1482 glDisable(GL_BLEND);
1487 /* store coord and continue, we need coordinates for elements outside view too */
1490 te->xend = startx + offsx;
1492 if (TSELEM_OPEN(tselem, soops)) {
1493 *starty -= UI_UNIT_Y;
1495 for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
1496 /* check if element needs to be drawn grayed out, but also gray out
1497 * childs of a grayed out parent (pass on draw_grayed_out to childs) */
1498 bool draw_childs_grayed_out = draw_grayed_out || (ten->drag_data != NULL);
1499 outliner_draw_tree_element(C, block, fstyle, scene, sl, ar, soops, ten, draw_childs_grayed_out,
1500 startx + UI_UNIT_X, starty, te_edit, te_floating);
1504 for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
1505 outliner_set_coord_tree_element(ten, startx, *starty);
1508 *starty -= UI_UNIT_Y;
1512 static void outliner_draw_tree_element_floating(
1513 const ARegion *ar, const TreeElement *te_floating)
1515 const TreeElement *te_insert = te_floating->drag_data->insert_handle;
1516 const int line_width = 2;
1518 unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1519 int coord_y = te_insert->ys;
1520 int coord_x = te_insert->xs;
1523 if (te_insert == te_floating) {
1524 /* don't draw anything */
1528 UI_GetThemeColorShade4fv(TH_BACK, -40, col);
1529 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1532 if (ELEM(te_floating->drag_data->insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) {
1533 if (te_floating->drag_data->insert_type == TE_INSERT_BEFORE) {
1534 coord_y += UI_UNIT_Y;
1536 immUniformColor4fv(col);
1537 glLineWidth(line_width);
1539 immBegin(GWN_PRIM_LINE_STRIP, 2);
1540 immVertex2f(pos, coord_x, coord_y);
1541 immVertex2f(pos, ar->v2d.cur.xmax, coord_y);
1545 BLI_assert(te_floating->drag_data->insert_type == TE_INSERT_INTO);
1546 immUniformColor3fvAlpha(col, col[3] * 0.5f);
1548 immBegin(GWN_PRIM_TRI_STRIP, 4);
1549 immVertex2f(pos, coord_x, coord_y + UI_UNIT_Y);
1550 immVertex2f(pos, coord_x, coord_y);
1551 immVertex2f(pos, ar->v2d.cur.xmax, coord_y + UI_UNIT_Y);
1552 immVertex2f(pos, ar->v2d.cur.xmax, coord_y);
1556 glDisable(GL_BLEND);
1560 static void outliner_draw_hierarchy_lines_recursive(unsigned pos, SpaceOops *soops, ListBase *lb, int startx,
1561 const unsigned char col[4], bool draw_grayed_out,
1565 TreeStoreElem *tselem;
1568 if (BLI_listbase_is_empty(lb)) {
1572 const unsigned char grayed_alpha = col[3] / 2;
1574 y1 = y2 = *starty; /* for vertical lines between objects */
1575 for (te = lb->first; te; te = te->next) {
1576 bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL);
1578 tselem = TREESTORE(te);
1580 if (draw_childs_grayed_out) {
1581 immUniformColor3ubvAlpha(col, grayed_alpha);
1584 immUniformColor4ubv(col);
1587 /* horizontal line? */
1588 if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE))
1589 immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1);
1591 *starty -= UI_UNIT_Y;
1593 if (TSELEM_OPEN(tselem, soops))
1594 outliner_draw_hierarchy_lines_recursive(pos, soops, &te->subtree, startx + UI_UNIT_X,
1595 col, draw_childs_grayed_out, starty);
1598 if (draw_grayed_out) {
1599 immUniformColor3ubvAlpha(col, grayed_alpha);
1602 immUniformColor4ubv(col);
1607 if (te->parent || lb->first != lb->last) {
1608 tselem = TREESTORE(te);
1609 if (tselem->type == 0 && te->idcode == ID_OB)
1610 immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2);
1614 static void outliner_draw_hierarchy_lines(SpaceOops *soops, ListBase *lb, int startx, int *starty)
1616 Gwn_VertFormat *format = immVertexFormat();
1617 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
1618 unsigned char col[4];
1620 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1621 UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col);
1625 outliner_draw_hierarchy_lines_recursive(pos, soops, lb, startx, col, false, starty);
1626 glDisable(GL_BLEND);
1631 static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *lb, int *starty)
1634 TreeStoreElem *tselem;
1636 for (te = lb->first; te; te = te->next) {
1637 tselem = TREESTORE(te);
1639 /* selection status */
1640 if (TSELEM_OPEN(tselem, soops))
1641 if (tselem->type == TSE_RNA_STRUCT) {
1642 Gwn_VertFormat *format = immVertexFormat();
1643 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
1644 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1645 immThemeColorShadeAlpha(TH_BACK, -15, -200);
1646 immRecti(pos, 0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
1650 *starty -= UI_UNIT_Y;
1651 if (TSELEM_OPEN(tselem, soops)) {
1652 outliner_draw_struct_marks(ar, soops, &te->subtree, starty);
1653 if (tselem->type == TSE_RNA_STRUCT) {
1654 Gwn_VertFormat *format = immVertexFormat();
1655 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1656 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1657 immThemeColorShadeAlpha(TH_BACK, -15, -200);
1659 immBegin(GWN_PRIM_LINES, 2);
1660 immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y);
1661 immVertex2f(pos, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y);
1670 static void outliner_draw_highlights_recursive(
1671 unsigned pos, const ARegion *ar, const SpaceOops *soops, const ListBase *lb,
1672 const float col_selection[4], const float col_highlight[4], const float col_searchmatch[4],
1673 int start_x, int *io_start_y)
1675 const bool is_searching = SEARCHING_OUTLINER(soops) ||
1676 (soops->outlinevis == SO_DATABLOCKS && soops->search_string[0] != 0);
1678 for (TreeElement *te = lb->first; te; te = te->next) {
1679 const TreeStoreElem *tselem = TREESTORE(te);
1680 const int start_y = *io_start_y;
1682 /* selection status */
1683 if (tselem->flag & TSE_SELECTED) {
1684 immUniformColor4fv(col_selection);
1685 immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
1688 /* search match highlights
1689 * we don't expand items when searching in the datablocks but we
1690 * still want to highlight any filter matches. */
1691 if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) {
1692 immUniformColor4fv(col_searchmatch);
1693 immRecti(pos, start_x, start_y + 1, ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
1696 /* mouse hover highlights */
1697 if ((tselem->flag & TSE_HIGHLIGHTED) || (te->drag_data != NULL)) {
1698 immUniformColor4fv(col_highlight);
1699 immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1);
1702 *io_start_y -= UI_UNIT_Y;
1703 if (TSELEM_OPEN(tselem, soops)) {
1704 outliner_draw_highlights_recursive(
1705 pos, ar, soops, &te->subtree, col_selection, col_highlight, col_searchmatch,
1706 start_x + UI_UNIT_X, io_start_y);
1711 static void outliner_draw_highlights(ARegion *ar, SpaceOops *soops, int startx, int *starty)
1713 const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
1714 float col_selection[4], col_searchmatch[4];
1716 UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection);
1717 col_selection[3] = 1.0f; /* no alpha */
1718 UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
1719 col_searchmatch[3] = 0.5f;
1722 Gwn_VertFormat *format = immVertexFormat();
1723 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
1724 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1725 outliner_draw_highlights_recursive(pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch,
1728 glDisable(GL_BLEND);
1731 static void outliner_draw_tree(
1732 bContext *C, uiBlock *block, Scene *scene, SceneLayer *sl, ARegion *ar,
1733 SpaceOops *soops, const bool has_restrict_icons,
1734 TreeElement **te_edit)
1736 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
1737 TreeElement *te_floating = NULL;
1740 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once
1742 if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
1744 starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
1745 outliner_draw_struct_marks(ar, soops, &soops->tree, &starty);
1748 /* draw highlights before hierarchy */
1749 starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
1751 outliner_draw_highlights(ar, soops, startx, &starty);
1753 /* set scissor so tree elements or lines can't overlap restriction icons */
1754 GLfloat scissor[4] = {0};
1755 if (has_restrict_icons) {
1756 int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1;
1757 CLAMP_MIN(mask_x, 0);
1759 glGetFloatv(GL_SCISSOR_BOX, scissor);
1760 glScissor(ar->winrct.xmin, ar->winrct.ymin, mask_x, ar->winy);
1763 // gray hierarchy lines
1765 starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
1767 outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty);
1770 starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
1772 for (TreeElement *te = soops->tree.first; te; te = te->next) {
1773 outliner_draw_tree_element(C, block, fstyle, scene, sl, ar, soops, te, te->drag_data != NULL,
1774 startx, &starty, te_edit, &te_floating);
1776 if (te_floating && te_floating->drag_data->insert_handle) {
1777 outliner_draw_tree_element_floating(ar, te_floating);
1780 if (has_restrict_icons) {
1782 glScissor(UNPACK4(scissor));
1787 static void outliner_back(ARegion *ar)
1791 ystart = (int)ar->v2d.tot.ymax;
1792 ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
1794 Gwn_VertFormat *format = immVertexFormat();
1795 unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
1797 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1798 immUniformThemeColorShade(TH_BACK, 6);
1800 const float x1 = 0.0f, x2 = ar->v2d.cur.xmax;
1801 float y1 = ystart, y2;
1802 int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y);
1805 immBegin(GWN_PRIM_TRIS, 6 * tot);
1807 y1 -= 2 * UI_UNIT_Y;
1808 y2 = y1 + UI_UNIT_Y;
1809 immVertex2f(pos, x1, y1);
1810 immVertex2f(pos, x2, y1);
1811 immVertex2f(pos, x2, y2);
1813 immVertex2f(pos, x1, y1);
1814 immVertex2f(pos, x2, y2);
1815 immVertex2f(pos, x1, y2);
1822 static void outliner_draw_restrictcols(ARegion *ar)
1826 unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
1827 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
1828 immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
1829 immBegin(GWN_PRIM_LINES, 6);
1832 immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax);
1833 immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin);
1836 immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax);
1837 immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin);
1840 immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax);
1841 immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin);
1847 /* ****************************************************** */
1848 /* Main Entrypoint - Draw contents of Outliner editor */
1850 void draw_outliner(const bContext *C)
1852 Main *mainvar = CTX_data_main(C);
1853 Scene *scene = CTX_data_scene(C);
1854 SceneLayer *sl = CTX_data_scene_layer(C);
1855 ARegion *ar = CTX_wm_region(C);
1856 View2D *v2d = &ar->v2d;
1857 SpaceOops *soops = CTX_wm_space_outliner(C);
1859 int sizey = 0, sizex = 0, sizex_rna = 0;
1860 TreeElement *te_edit = NULL;
1861 bool has_restrict_icons;
1863 outliner_build_tree(mainvar, scene, sl, soops); // always
1865 /* get extents of data */
1866 outliner_height(soops, &soops->tree, &sizey);
1868 if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
1869 /* RNA has two columns:
1870 * - column 1 is (max_width + OL_RNA_COL_SPACEX) or
1871 * (OL_RNA_COL_X), whichever is wider...
1872 * - column 2 is fixed at OL_RNA_COL_SIZEX
1874 * (*) XXX max width for now is a fixed factor of (UI_UNIT_X * (max_indention + 100))
1877 /* get actual width of column 1 */
1878 outliner_rna_width(soops, &soops->tree, &sizex_rna, 0);
1879 sizex_rna = max_ii(OL_RNA_COLX, sizex_rna + OL_RNA_COL_SPACEX);
1881 /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */
1882 sizex = sizex_rna + OL_RNA_COL_SIZEX + 50;
1883 has_restrict_icons = false;
1886 /* width must take into account restriction columns (if visible) so that entries will still be visible */
1887 //outliner_width(soops, &soops->tree, &sizex);
1888 // XXX should use outliner_width instead when te->xend will be set correctly...
1889 outliner_rna_width(soops, &soops->tree, &sizex, 0);
1891 /* constant offset for restriction columns */
1892 // XXX this isn't that great yet...
1893 if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
1894 sizex += OL_TOGW * 3;
1896 has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS);
1899 /* adds vertical offset */
1900 sizey += OL_Y_OFFSET;
1902 /* update size of tot-rect (extents of data/viewable area) */
1903 UI_view2d_totRect_set(v2d, sizex, sizey);
1905 /* force display to pixel coords */
1906 v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y);
1907 /* set matrix for 2d-view controls */
1908 UI_view2d_view_ortho(v2d);
1910 /* draw outliner stuff (background, hierarchy lines and names) */
1912 block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
1913 outliner_draw_tree((bContext *)C, block, scene, sl, ar, soops, has_restrict_icons, &te_edit);
1915 if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
1916 /* draw rna buttons */
1917 outliner_draw_rnacols(ar, sizex_rna);
1918 outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree);
1920 else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) {
1921 /* draw user toggle columns */
1922 outliner_draw_restrictcols(ar);
1923 outliner_draw_userbuts(block, ar, soops, &soops->tree);
1925 else if (has_restrict_icons) {
1926 /* draw restriction columns */
1927 outliner_draw_restrictcols(ar);
1928 outliner_draw_restrictbuts(block, scene, ar, soops, &soops->tree);
1931 /* draw edit buttons if nessecery */
1933 outliner_buttons(C, block, ar, te_edit);
1936 UI_block_end(C, block);
1937 UI_block_draw(C, block);
1939 /* clear flag that allows quick redraws */
1940 soops->storeflag &= ~SO_TREESTORE_REDRAW;