WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
4 changed files with 149 additions and 18 deletions
Showing only changes of commit 03155f1316 - Show all commits

View File

@ -1246,6 +1246,14 @@ def km_outliner(params):
{"properties": [("extend_range", True), ("deselect_all", not params.legacy)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True, "shift": True},
{"properties": [("extend", True), ("extend_range", True), ("deselect_all", not params.legacy)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("recurse", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "ctrl": True},
{"properties": [("recurse", True), ("extend", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True},
{"properties": [("recurse", True), ("extend_range", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "ctrl": True, "shift": True},
{"properties": [("recurse", True), ("extend", True), ("extend_range", True), ("deselect_all", True)]}),
("outliner.select_box", {"type": 'B', "value": 'PRESS'}, None),
("outliner.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, {"properties": [("tweak", True)]}),
("outliner.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},

View File

@ -486,6 +486,14 @@ def km_outliner(params):
{"properties": [("extend", False), ("extend_range", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True, "shift": True},
{"properties": [("extend", True), ("extend_range", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("recurse", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "ctrl": True},
{"properties": [("recurse", True), ("extend", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True},
{"properties": [("recurse", True), ("extend_range", True), ("deselect_all", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "ctrl": True, "shift": True},
{"properties": [("recurse", True), ("extend", True), ("extend_range", True), ("deselect_all", True)]}),
("outliner.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, {"properties": [("tweak", True)]}),
("outliner.select_box", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "shift": True},
{"properties": [("tweak", True), ("mode", 'ADD')]}),

View File

@ -413,7 +413,7 @@ static int outliner_item_rename_invoke(bContext *C, wmOperator *op, const wmEven
TreeElement *te = use_active ? outliner_item_rename_find_active(space_outliner, op->reports) :
outliner_item_rename_find_hovered(space_outliner, region, event);
if (!te) {
return OPERATOR_CANCELLED;
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
/* Force element into view. */

View File

@ -1569,30 +1569,84 @@ void outliner_item_select(bContext *C,
}
}
static bool can_select_recursive(TreeElement *te, Collection *in_collection)
{
if (te->store_elem->type == TSE_LAYER_COLLECTION) {
return true;
}
if (te->store_elem->type == TSE_SOME_ID && te->idcode == ID_OB) {
/* Only actually select the object if
* 1. We are not restricted to any collection, or
* 2. The object is in fact in the given collection. */
if (!in_collection || BKE_collection_has_object_recursive(
in_collection, reinterpret_cast<Object *>(te->store_elem->id)))
{
return true;
}
}
return false;
}
static void do_outliner_select_recursive(ListBase *lb, bool selecting, Collection *in_collection)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
/* Recursive selection only on collections or objects. */
if (can_select_recursive(te, in_collection)) {
tselem->flag = selecting ? (tselem->flag | TSE_SELECTED) : (tselem->flag & ~TSE_SELECTED);
if (tselem->type == TSE_LAYER_COLLECTION) {
/* Restrict sub-tree selections to this collection. This prevents undesirable behavior in
* the edge-case where there is an object which is part of this collection, but which has
* children that are part of another collection. */
do_outliner_select_recursive(
&te->subtree, selecting, static_cast<LayerCollection *>(te->directdata)->collection);
}
else {
do_outliner_select_recursive(&te->subtree, selecting, in_collection);
}
}
else {
tselem->flag &= ~TSE_SELECTED;
}
}
}
static bool do_outliner_range_select_recursive(ListBase *lb,
TreeElement *active,
TreeElement *cursor,
bool selecting)
bool selecting,
const bool recurse,
Collection *in_collection)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (selecting) {
tselem->flag |= TSE_SELECTED;
}
bool can_select = !recurse || can_select_recursive(te, in_collection);
/* Remember if we are selecting before we potentially change the selecting state. */
bool selecting_before = selecting;
/* Set state for selection */
if (ELEM(te, active, cursor)) {
selecting = !selecting;
}
if (selecting) {
if (can_select && (selecting_before || selecting)) {
tselem->flag |= TSE_SELECTED;
}
/* Don't look inside closed elements */
if (!(tselem->flag & TSE_CLOSED)) {
selecting = do_outliner_range_select_recursive(&te->subtree, active, cursor, selecting);
/* Don't look inside closed elements, unless we're forcing the recursion all the way down. */
if (!(tselem->flag & TSE_CLOSED) || recurse) {
/* If this tree element is a collection, then it sets
* the precedent for inclusion of its subobjects. */
Collection *child_collection = in_collection;
if (tselem->type == TSE_LAYER_COLLECTION) {
child_collection = static_cast<LayerCollection *>(te->directdata)->collection;
}
selecting = do_outliner_range_select_recursive(
&te->subtree, active, cursor, selecting, recurse, child_collection);
}
}
@ -1603,7 +1657,9 @@ static bool do_outliner_range_select_recursive(ListBase *lb,
static void do_outliner_range_select(bContext *C,
SpaceOutliner *space_outliner,
TreeElement *cursor,
const bool extend)
const bool extend,
const bool recurse,
Collection *in_collection)
{
TreeElement *active = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
@ -1632,7 +1688,8 @@ static void do_outliner_range_select(bContext *C,
return;
}
do_outliner_range_select_recursive(&space_outliner->tree, active, cursor, false);
do_outliner_range_select_recursive(
&space_outliner->tree, active, cursor, false, recurse, in_collection);
}
static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_outliner,
@ -1673,7 +1730,8 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
const int mval[2],
const bool extend,
const bool use_range,
const bool deselect_all)
const bool deselect_all,
const bool recurse)
{
ARegion *region = CTX_wm_region(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@ -1716,21 +1774,73 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
TreeStoreElem *activate_tselem = TREESTORE(activate_te);
/* If we're recursing, we need to know the collection of the selected item in order
* to prevent selecting across collection boundaries. (Object hierarchies might cross
* collection boundaries, i.e., children may be in different collections from their
* parents.) */
Collection *parent_collection = nullptr;
if (recurse) {
if (activate_tselem->type == TSE_LAYER_COLLECTION) {
parent_collection = static_cast<LayerCollection *>(activate_te->directdata)->collection;
}
else if (activate_tselem->type == TSE_SOME_ID && activate_te->idcode == ID_OB) {
parent_collection = BKE_collection_object_find(
CTX_data_main(C),
CTX_data_scene(C),
nullptr,
reinterpret_cast<Object *>(activate_tselem->id));
}
}
/* If we're not recursing (not double clicking), and we are extending or range selecting by
* holding CTRL or SHIFT, ignore events when the cursor is over the icon. This disambiguates
* the case where we are recursing *and* holding CTRL or SHIFT in order to extend or range
* select recursively. */
if (!recurse && (extend || use_range) &&
outliner_item_is_co_over_icon(activate_te, view_mval[0]))
{
return OPERATOR_CANCELLED;
}
if (use_range) {
do_outliner_range_select(C, space_outliner, activate_te, extend);
do_outliner_range_select(C, space_outliner, activate_te, extend, recurse, parent_collection);
if (recurse) {
do_outliner_select_recursive(&activate_te->subtree, true, parent_collection);
}
}
else {
const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te,
view_mval[0]);
/* Always select unless already active and selected */
const bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE &&
activate_tselem->flag & TSE_SELECTED);
/* Always select unless already active and selected. */
bool select = !extend || !(activate_tselem->flag & TSE_ACTIVE) ||
!(activate_tselem->flag & TSE_SELECTED);
/* If we're CTRL+double-clicking and the element is aleady
* selected, skip the activation and go straight to deselection. */
if (extend && recurse && activate_tselem->flag & TSE_SELECTED) {
select = false;
}
const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) |
(is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) |
(extend ? OL_ITEM_EXTEND : 0);
outliner_item_select(C, space_outliner, activate_te, select_flag);
/* The recurse flag is set when the user double-clicks
* to select everything in a collection or hierarchy. */
if (recurse) {
if (outliner_item_is_co_over_icon(activate_te, view_mval[0])) {
/* Select or deselect object hierarchy recursively. */
outliner_item_select(C, space_outliner, activate_te, select_flag);
do_outliner_select_recursive(&activate_te->subtree, select, parent_collection);
}
else {
/* Double-clicked, but it wasn't on the icon. */
return OPERATOR_CANCELLED;
}
}
else {
outliner_item_select(C, space_outliner, activate_te, select_flag);
}
/* Only switch properties editor tabs when icons are selected. */
if (is_over_icon) {
@ -1765,10 +1875,11 @@ static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEv
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
const bool recurse = RNA_boolean_get(op->ptr, "recurse");
int mval[2];
WM_event_drag_start_mval(event, region, mval);
return outliner_item_do_activate_from_cursor(C, mval, extend, use_range, deselect_all);
return outliner_item_do_activate_from_cursor(C, mval, extend, use_range, deselect_all, recurse);
}
void OUTLINER_OT_item_activate(wmOperatorType *ot)
@ -1796,6 +1907,10 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
"Deselect On Nothing",
"Deselect all when nothing under the cursor");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "recurse", false, "Recurse", "Select objects recursively from active element");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */