Merge branch 'master' into blender2.8
authorJulian Eisel <eiseljulian@gmail.com>
Sun, 16 Oct 2016 13:33:00 +0000 (15:33 +0200)
committerJulian Eisel <eiseljulian@gmail.com>
Sun, 16 Oct 2016 13:33:00 +0000 (15:33 +0200)
Conflicts:
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_select.c

1  2 
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/editors/space_outliner/outliner_intern.h
source/blender/editors/space_outliner/outliner_select.c
source/blender/editors/space_outliner/outliner_tools.c
source/blender/editors/space_outliner/outliner_tree.c

index 7306afc08ff31a14d1c7627142d81d570c7d32d0,33a5a7ca7b72d7493c1fd4d05c0a8c3f21490907..edda90a0c8319f7e742f65f3b2269cb65c7f6d0a
@@@ -1408,19 -1412,16 +1406,19 @@@ static void outliner_draw_iconrow(bCont
  }
  
  /* closed tree element */
- static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, int startx, int starty)
+ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty)
  {
        TreeElement *ten;
 -      
 -      /* store coord and continue, we need coordinates for elements outside view too */
 -      te->xs = startx;
 -      te->ys = starty;
 -      
 +
 +      /* closed items may be displayed in row of parent, don't change their coordinate! */
 +      if ((te->flag & TE_ICONROW) == 0) {
 +              /* store coord and continue, we need coordinates for elements outside view too */
 +              te->xs = startx;
 +              te->ys = starty;
 +      }
 +
        for (ten = te->subtree.first; ten; ten = ten->next) {
-               outliner_set_coord_tree_element(soops, ten, startx + UI_UNIT_X, starty);
+               outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty);
        }
  }
  
@@@ -1911,9 -1887,9 +1909,9 @@@ void draw_outliner(const bContext *C
        if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
                /* draw rna buttons */
                outliner_draw_rnacols(ar, sizex_rna);
-               outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree);
+               outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree);
        }
 -      else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) {
 +      else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) {
                /* draw user toggle columns */
                outliner_draw_restrictcols(ar);
                outliner_draw_userbuts(block, ar, soops, &soops->tree);
index 87e6be76de86fdb36a4cd5f4ba12cfeb37482ad2,345ac353c11594a0c384e8e59ab49b2a8236347c..4dcdcc69d6d68d80cfbadd486efae5c3e797fb90
@@@ -150,95 -148,8 +148,95 @@@ TreeElement *outliner_dropzone_find(con
        return NULL;
  }
  
 +/**
 + * Try to find an item under y-coordinate \a view_co_y (view-space).
 + * \note Recursive
 + */
 +TreeElement *outliner_find_item_at_y(const SpaceOops *soops, const ListBase *tree, float view_co_y)
 +{
 +      for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) {
 +              if (view_co_y < (te_iter->ys + UI_UNIT_Y)) {
 +                      if (view_co_y > te_iter->ys) {
 +                              /* co_y is inside this element */
 +                              return te_iter;
 +                      }
 +                      else if (TSELEM_OPEN(te_iter->store_elem, soops)) {
 +                              /* co_y is lower than current element, possibly inside children */
 +                              TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y);
 +                              if (te_sub) {
 +                                      return te_sub;
 +                              }
 +                      }
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +/**
 + * Collapsed items can show their children as click-able icons. This function tries to find
 + * such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
 + *
 + * \return a hovered child item or \a parent_te (if no hovered child found).
 + */
 +TreeElement *outliner_find_item_at_x_in_row(const SpaceOops *soops, const TreeElement *parent_te, float view_co_x)
 +{
 +      if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) { /* if parent_te is opened, it doesn't show childs in row */
 +              /* no recursion, items can only display their direct children in the row */
 +              for (TreeElement *child_te = parent_te->subtree.first;
 +                   child_te && view_co_x >= child_te->xs; /* don't look further if co_x is smaller than child position*/
 +                   child_te = child_te->next)
 +              {
 +                      if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) && (view_co_x < child_te->xend)) {
 +                              return child_te;
 +                      }
 +              }
 +      }
 +
 +      /* return parent if no child is hovered */
 +      return (TreeElement *)parent_te;
 +}
 +
 +
  /* ************************************************************** */
 -/* Click Activated */
 +
 +/* Highlight --------------------------------------------------- */
 +
 +static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
 +
 +      TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my);
 +      bool changed = false;
 +
 +      if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
-               changed = outliner_set_flag(soops, &soops->tree, TSE_HIGHLIGHTED, false);
++              changed = outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false);
 +              if (hovered_te) {
 +                      hovered_te->store_elem->flag |= TSE_HIGHLIGHTED;
 +                      changed = true;
 +              }
 +      }
 +
 +      if (changed) {
 +              soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
 +              ED_region_tag_redraw(ar);
 +      }
 +
 +      return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
 +}
 +
 +void OUTLINER_OT_highlight_update(wmOperatorType *ot)
 +{
 +      ot->name = "Update Highlight";
 +      ot->idname = "OUTLINER_OT_highlight_update";
 +      ot->description = "Update the item highlight based on the current mouse position";
 +
 +      ot->invoke = outliner_highlight_update;
 +
 +      ot->poll = ED_operator_outliner_active;
 +}
  
  /* Toggle Open/Closed ------------------------------------------- */
  
@@@ -829,34 -740,17 +827,34 @@@ int outliner_has_one_flag(ListBase *lb
        return 0;
  }
  
 -void outliner_set_flag(ListBase *lb, short flag, short set)
 +/**
 + * Set or unset \a flag for all outliner elements in \a lb and sub-trees.
 + * \return if any flag was modified.
 + */
- bool outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
++bool outliner_set_flag(ListBase *lb, short flag, short set)
  {
        TreeElement *te;
        TreeStoreElem *tselem;
 -      
 +      bool changed = false;
 +      bool has_flag;
 +
        for (te = lb->first; te; te = te->next) {
                tselem = TREESTORE(te);
 -              if (set == 0) tselem->flag &= ~flag;
 -              else tselem->flag |= flag;
 -              outliner_set_flag(&te->subtree, flag, set);
 +              has_flag = (tselem->flag & flag);
 +              if (set == 0) {
 +                      if (has_flag) {
 +                              tselem->flag &= ~flag;
 +                              changed = true;
 +                      }
 +              }
 +              else if (!has_flag){
 +                      tselem->flag |= flag;
 +                      changed = true;
 +              }
-               changed |= outliner_set_flag(soops, &te->subtree, flag, set);
++              changed |= outliner_set_flag(&te->subtree, flag, set);
        }
 +
 +      return changed;
  }
  
  /* Restriction Columns ------------------------------- */
index db614631bf77ba7c77f89deeefe7bd36f760ad78,ccc52f2dba825a5fb2c954348f9ccadc804bd956..c5dfbf1819b624c23749c4bdb7f71e0a19c52de5
@@@ -170,8 -166,8 +170,8 @@@ void outliner_do_object_operation
  
  int common_restrict_check(struct bContext *C, struct Object *ob);
  
- int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel);
- bool outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set);
+ int outliner_has_one_flag(ListBase *lb, short flag, const int curlevel);
 -void outliner_set_flag(ListBase *lb, short flag, short set);
++bool outliner_set_flag(ListBase *lb, short flag, short set);
  
  void object_toggle_visibility_cb(
          struct bContext *C, struct ReportList *reports, struct Scene *scene,
index 635c792323674e0c61adacb93a7072e851a58fd5,89df471990aae8c51bf5b4a768f949e4d0e61b88..101ad235428db5f147b667d41050c195b5df1a72
@@@ -821,115 -886,110 +821,115 @@@ eOLDrawState tree_element_type_active
  
  /* ================================================ */
  
 -static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, SpaceOops *soops,
 -                                      TreeElement *te, bool extend, bool recursive, const float mval[2])
 +static void outliner_item_activate(
 +        bContext *C, SpaceOops *soops, TreeElement *te,
 +        const bool extend, const bool recursive)
  {
 -      
 -      if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
 -              TreeStoreElem *tselem = TREESTORE(te);
 -              bool openclose = false;
 -              
 -              /* open close icon */
 -              if ((te->flag & TE_ICONROW) == 0) {               // hidden icon, no open/close
 -                      if (mval[0] > te->xs && mval[0] < te->xs + UI_UNIT_X)
 -                              openclose = true;
 -              }
 -              
 -              if (openclose) {
 -                      /* all below close/open? */
 -                      if (extend) {
 -                              tselem->flag &= ~TSE_CLOSED;
 -                              outliner_set_flag(&te->subtree, TSE_CLOSED, !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1));
 -                      }
 -                      else {
 -                              if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
 -                              else tselem->flag |= TSE_CLOSED;
 -                              
 +      Scene *scene = CTX_data_scene(C);
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      /* always makes active object, except for some specific types.
 +       * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want
 +       * to switch out of edit mode (see T48328 for details). */
 +      if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) {
 +              tree_element_set_active_object(C, scene, soops, te,
 +                                             (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
 +                                             recursive && tselem->type == 0);
 +      }
 +
 +      if (tselem->type == 0) { // the lib blocks
 +              /* editmode? */
 +              if (te->idcode == ID_SCE) {
 +                      if (scene != (Scene *)tselem->id) {
 +                              ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
                        }
 -                      
 -                      return true;
                }
 -              /* name and first icon */
 -              else if (mval[0] > te->xs + UI_UNIT_X && mval[0] < te->xend) {
 -                      
 -                      /* always makes active object, except for some specific types.
 -                       * Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want
 -                       * to switch out of edit mode (see T48328 for details). */
 -                      if (!ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE)) {
 -                              tree_element_set_active_object(C, scene, soops, te,
 -                                                             (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
 -                                                             recursive && tselem->type == 0);
 -                      }
 +              else if (te->idcode == ID_GR) {
 +                      Group *gr = (Group *)tselem->id;
 +                      GroupObject *gob;
                        
 -                      if (tselem->type == 0) { // the lib blocks
 -                              /* editmode? */
 -                              if (te->idcode == ID_SCE) {
 -                                      if (scene != (Scene *)tselem->id) {
 -                                              ED_screen_set_scene(C, CTX_wm_screen(C), (Scene *)tselem->id);
 -                                      }
 -                              }
 -                              else if (te->idcode == ID_GR) {
 -                                      Group *gr = (Group *)tselem->id;
 -                                      GroupObject *gob;
 -                                      
 -                                      if (extend) {
 -                                              int sel = BA_SELECT;
 -                                              for (gob = gr->gobject.first; gob; gob = gob->next) {
 -                                                      if (gob->ob->flag & SELECT) {
 -                                                              sel = BA_DESELECT;
 -                                                              break;
 -                                                      }
 -                                              }
 -                                              
 -                                              for (gob = gr->gobject.first; gob; gob = gob->next) {
 -                                                      ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel);
 -                                              }
 -                                      }
 -                                      else {
 -                                              BKE_scene_base_deselect_all(scene);
 -                                              
 -                                              for (gob = gr->gobject.first; gob; gob = gob->next) {
 -                                                      if ((gob->ob->flag & SELECT) == 0)
 -                                                              ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT);
 -                                              }
 +                      if (extend) {
 +                              int sel = BA_SELECT;
 +                              for (gob = gr->gobject.first; gob; gob = gob->next) {
 +                                      if (gob->ob->flag & SELECT) {
 +                                              sel = BA_DESELECT;
 +                                              break;
                                        }
 -                                      
 -                                      WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 -                              }
 -                              else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
 -                                      WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
 -                              }
 -                              else {  // rest of types
 -                                      tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false);
                                }
  
 +                              for (gob = gr->gobject.first; gob; gob = gob->next) {
 +                                      ED_base_object_select(BKE_scene_base_find(scene, gob->ob), sel);
 +                              }
                        }
                        else {
 -                              tree_element_type_active(C, scene, soops, te, tselem,
 -                                                       extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
 -                                                       recursive);
 +                              BKE_scene_base_deselect_all(scene);
 +
 +                              for (gob = gr->gobject.first; gob; gob = gob->next) {
 +                                      if ((gob->ob->flag & SELECT) == 0)
 +                                              ED_base_object_select(BKE_scene_base_find(scene, gob->ob), BA_SELECT);
 +                              }
                        }
                        
 -                      return true;
 +                      WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
                }
 -      }
 -      
 -      for (te = te->subtree.first; te; te = te->next) {
 -              if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, mval)) {
 -                      return true;
 +              else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
 +                      WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
 +              }
 +              else {  // rest of types
 +                      tree_element_active(C, scene, soops, te, OL_SETSEL_NORMAL, false);
                }
 +
 +      }
 +      else {
 +              tree_element_type_active(C, scene, soops, te, tselem,
 +                                       extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
 +                                       recursive);
        }
 -      return false;
  }
  
 -int outliner_item_do_activate(bContext *C, int x, int y, bool extend, bool recursive)
 +/**
 + * \param extend: Don't deselect other items, only modify \a te.
 + * \param toggle: Select \a te when not selected, deselect when selected.
 + */
 +static void outliner_item_select(SpaceOops *soops, const TreeElement *te, const bool extend, const bool toggle)
 +{
 +      TreeStoreElem *tselem = TREESTORE(te);
 +      const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
 +
 +      if (extend == false) {
-               outliner_set_flag(soops, &soops->tree, TSE_SELECTED, false);
++              outliner_set_flag(&soops->tree, TSE_SELECTED, false);
 +      }
 +      tselem->flag = new_flag;
 +}
 +
- static void outliner_item_toggle_closed(SpaceOops *soops, TreeElement *te, const bool toggle_children)
++static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children)
 +{
 +      TreeStoreElem *tselem = TREESTORE(te);
 +      if (toggle_children) {
 +              tselem->flag &= ~TSE_CLOSED;
 +
-               const bool all_opened = !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1);
-               outliner_set_flag(soops, &te->subtree, TSE_CLOSED, all_opened);
++              const bool all_opened = !outliner_has_one_flag(&te->subtree, TSE_CLOSED, 1);
++              outliner_set_flag(&te->subtree, TSE_CLOSED, all_opened);
 +      }
 +      else {
 +              tselem->flag ^= TSE_CLOSED;
 +      }
 +}
 +
 +static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
 +{
 +      return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
 +}
 +
 +static bool outliner_is_co_within_restrict_columns(const SpaceOops *soops, const ARegion *ar, float view_co_x)
 +{
 +      return (!ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF) &&
 +              !(soops->flag & SO_HIDE_RESTRICTCOLS) &&
 +              (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX));
 +}
 +
 +int outliner_item_activate_or_toggle_closed(bContext *C, int x, int y, bool extend, bool recursive)
  {
 -      Scene *scene = CTX_data_scene(C);
        ARegion *ar = CTX_wm_region(C);
        SpaceOops *soops = CTX_wm_space_outliner(C);
        TreeElement *te;
                return OPERATOR_CANCELLED;
        }
  
 -      for (te = soops->tree.first; te; te = te->next) {
 -              if (do_outliner_item_activate(C, scene, ar, soops, te, extend, recursive, fmval)) break;
 +      if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) {
 +              /* skip */
        }
 -      
 -      if (te) {
 -              ED_undo_push(C, "Outliner click event");
 +      else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
-               outliner_item_toggle_closed(soops, te, extend);
++              outliner_item_toggle_closed(te, extend);
 +              changed = true;
        }
        else {
 -              short selecting = -1;
 -              int row;
 -              
 -              /* get row number - 100 here is just a dummy value since we don't need the column */
 -              UI_view2d_listview_view_to_cell(&ar->v2d, 1000, UI_UNIT_Y, 0.0f, OL_Y_OFFSET, 
 -                                              fmval[0], fmval[1], NULL, &row);
 -              
 -              /* select relevant row */
 -              if (outliner_select(soops, &soops->tree, &row, &selecting)) {
 -              
 -                      soops->storeflag |= SO_TREESTORE_REDRAW;
 -              
 -                      /* no need for undo push here, only changing outliner data which is
 -                       * scene level - campbell */
 -                      /* ED_undo_push(C, "Outliner selection event"); */
 -              }
 +              /* the row may also contain children, if one is hovered we want this instead of current te */
 +              TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]);
 +
 +              outliner_item_select(soops, activate_te, extend, extend);
 +              outliner_item_activate(C, soops, activate_te, extend, recursive);
 +              changed = true;
 +      }
 +
 +      if (changed) {
 +              soops->storeflag |= SO_TREESTORE_REDRAW; /* only needs to redraw, no rebuild */
 +              ED_undo_push(C, "Outliner selection change");
 +              ED_region_tag_redraw(ar);
        }
 -      
 -      ED_region_tag_redraw(ar);
  
        return OPERATOR_FINISHED;
  }