GPv3: Initial Layer Tree UI #109197

Merged
Falk David merged 26 commits from filedescriptor/blender:gpv3-layer-tree-ui into main 2023-06-22 10:51:51 +02:00
18 changed files with 583 additions and 18 deletions

View File

@ -22,6 +22,7 @@ _modules = [
"properties_data_curves",
"properties_data_empty",
"properties_data_gpencil",
"properties_data_grease_pencil",
"properties_data_light",
"properties_data_lattice",
"properties_data_mesh",

View File

@ -0,0 +1,56 @@
# SPDX-FileCopyrightText: 2023 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Panel
class DataButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
return hasattr(context, "grease_pencil") and context.grease_pencil
class DATA_PT_context_grease_pencil(DataButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
def draw(self, context):
layout = self.layout
ob = context.object
grease_pencil = context.grease_pencil
space = context.space_data
if ob:
layout.template_ID(ob, "data")
elif grease_pencil:
layout.template_ID(space, "pin_id")
class DATA_PT_grease_pencil_layers(DataButtonsPanel, Panel):
bl_label = "Layers"
def draw(self, context):
layout = self.layout
row = layout.row()
row.template_grease_pencil_layer_tree()
col = row.column()
col.operator("grease_pencil.layer_add", icon='ADD', text="")
col.operator("grease_pencil.layer_remove", icon='REMOVE', text="")
classes = (
DATA_PT_context_grease_pencil,
DATA_PT_grease_pencil_layers,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)

View File

@ -183,10 +183,16 @@ class Layer : public ::GreasePencilLayer {
Layer(const Layer &other);
~Layer();
StringRefNull name() const
{
return this->base.name;
}
/**
* \returns the layer name.
*/
StringRefNull name() const;
void set_name(StringRefNull new_name);
/**
* \returns the parent layer group.
*/
LayerGroup &parent_group() const;
/**
* \returns the frames mapping.
@ -257,6 +263,11 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
~LayerGroup();
public:
StringRefNull name() const
{
return this->base.name;
}
/**
* Adds a group at the end of this group.
*/
@ -269,6 +280,18 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
Layer &add_layer(Layer *layer);
Layer &add_layer(StringRefNull name);
/**
* Adds a layer before \a link and returns it.
*/
Layer &add_layer_before(Layer *layer, Layer *link);
Layer &add_layer_before(StringRefNull name, Layer *link);
/**
* Adds a layer after \a link and returns it.
*/
Layer &add_layer_after(Layer *layer, Layer *link);
Layer &add_layer_after(StringRefNull name, Layer *link);
/**
* Returns the number of direct nodes in this group.
*/
@ -285,6 +308,12 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
*/
void remove_child(int64_t index);
/**
* Tries to unlink the layer from the list of nodes in this group.
* \returns true, if the layer was successfully unlinked.
*/
bool unlink_layer(Layer *link);
/**
* Returns a `Span` of pointers to all the `TreeNode`s in this group.
*/
@ -313,6 +342,16 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
void tag_nodes_cache_dirty() const;
};
inline StringRefNull Layer::name() const
{
return this->base.name;
}
inline LayerGroup &Layer::parent_group() const
{
return this->base.parent->wrap();
}
namespace convert {
void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,

View File

@ -26,6 +26,9 @@
#include "BLI_span.hh"
#include "BLI_stack.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLI_string_utils.h"
#include "BLI_vector_set.hh"
#include "BLO_read_write.h"
@ -41,7 +44,7 @@
using blender::float3;
using blender::Span;
using blender::uint3;
using blender::Vector;
using blender::VectorSet;
static void grease_pencil_init_data(ID *id)
{
@ -108,8 +111,8 @@ static void grease_pencil_copy_data(Main * /*bmain*/,
/* Set active layer. */
if (grease_pencil_src->has_active_layer()) {
grease_pencil_dst->active_layer = grease_pencil_dst->find_layer_by_name(
grease_pencil_src->active_layer->wrap().name());
grease_pencil_dst->set_active_layer(
grease_pencil_dst->find_layer_by_name(grease_pencil_src->active_layer->wrap().name()));
}
/* Make sure the runtime pointer exists. */
@ -384,6 +387,11 @@ Layer::~Layer()
this->runtime = nullptr;
}
void Layer::set_name(StringRefNull new_name)
{
this->base.name = BLI_strdup(new_name.c_str());
}
const Map<int, GreasePencilFrame> &Layer::frames() const
{
return this->runtime->frames_;
@ -546,12 +554,46 @@ Layer &LayerGroup::add_layer(Layer *layer)
return *layer;
}
Layer &LayerGroup::add_layer_before(Layer *layer, Layer *link)
{
BLI_assert(layer != nullptr && link != nullptr);
BLI_insertlinkbefore(&this->children,
reinterpret_cast<GreasePencilLayerTreeNode *>(link),
reinterpret_cast<GreasePencilLayerTreeNode *>(layer));
layer->base.parent = reinterpret_cast<GreasePencilLayerTreeGroup *>(this);
this->tag_nodes_cache_dirty();
return *layer;
}
Layer &LayerGroup::add_layer_after(Layer *layer, Layer *link)
{
BLI_assert(layer != nullptr && link != nullptr);
BLI_insertlinkafter(&this->children,
reinterpret_cast<GreasePencilLayerTreeNode *>(link),
reinterpret_cast<GreasePencilLayerTreeNode *>(layer));
layer->base.parent = reinterpret_cast<GreasePencilLayerTreeGroup *>(this);
this->tag_nodes_cache_dirty();
return *layer;
}
Layer &LayerGroup::add_layer(StringRefNull name)
{
Layer *new_layer = MEM_new<Layer>(__func__, name);
return this->add_layer(new_layer);
}
Layer &LayerGroup::add_layer_before(StringRefNull name, Layer *link)
{
Layer *new_layer = MEM_new<Layer>(__func__, name);
return this->add_layer_before(new_layer, link);
}
Layer &LayerGroup::add_layer_after(StringRefNull name, Layer *link)
{
Layer *new_layer = MEM_new<Layer>(__func__, name);
return this->add_layer_after(new_layer, link);
}
int64_t LayerGroup::num_direct_nodes() const
{
return BLI_listbase_count(&this->children);
@ -570,6 +612,15 @@ void LayerGroup::remove_child(int64_t index)
this->tag_nodes_cache_dirty();
}
bool LayerGroup::unlink_layer(Layer *link)
{
if (BLI_remlink_safe(&this->children, link)) {
this->tag_nodes_cache_dirty();
return true;
}
return false;
}
Span<const TreeNode *> LayerGroup::nodes() const
{
this->ensure_nodes_cache();
@ -1143,13 +1194,81 @@ blender::Span<blender::bke::greasepencil::Layer *> GreasePencil::layers_for_writ
return this->root_group.wrap().layers_for_write();
}
blender::Span<const blender::bke::greasepencil::TreeNode *> GreasePencil::nodes() const
{
BLI_assert(this->runtime != nullptr);
return this->root_group.wrap().nodes();
}
const blender::bke::greasepencil::Layer *GreasePencil::get_active_layer() const
{
if (this->active_layer == nullptr) {
return nullptr;
}
return &this->active_layer->wrap();
}
blender::bke::greasepencil::Layer *GreasePencil::get_active_layer_for_write()
{
if (this->active_layer == nullptr) {
return nullptr;
}
return &this->active_layer->wrap();
}
void GreasePencil::set_active_layer(const blender::bke::greasepencil::Layer *layer)
{
this->active_layer = const_cast<GreasePencilLayer *>(
reinterpret_cast<const GreasePencilLayer *>(layer));
}
static blender::VectorSet<blender::StringRefNull> get_node_names(GreasePencil &grease_pencil)
{
using namespace blender;
VectorSet<StringRefNull> names;
for (const blender::bke::greasepencil::TreeNode *node : grease_pencil.nodes()) {
names.add(node->name);
}
return names;
}
static bool check_unique_layer_cb(void *arg, const char *name)
{
using namespace blender;
VectorSet<StringRefNull> &names = *reinterpret_cast<VectorSet<StringRefNull> *>(arg);
return names.contains(name);
}
static bool unique_layer_name(VectorSet<blender::StringRefNull> &names, char *name)
{
return BLI_uniquename_cb(check_unique_layer_cb, &names, "GP_Layer", '.', name, MAX_NAME);
}
blender::bke::greasepencil::Layer &GreasePencil::add_layer(
blender::bke::greasepencil::LayerGroup &group, const blender::StringRefNull name)
{
using namespace blender;
/* TODO: Check for name collisions and resolve them. */
/* StringRefNull checked_name; */
return group.add_layer(name);
VectorSet<StringRefNull> names = get_node_names(*this);
std::string unique_name(name.c_str());
unique_layer_name(names, unique_name.data());
return group.add_layer(unique_name);
}
blender::bke::greasepencil::Layer &GreasePencil::add_layer_after(
blender::bke::greasepencil::LayerGroup &group,
blender::bke::greasepencil::Layer *layer,
const blender::StringRefNull name)
{
using namespace blender;
VectorSet<StringRefNull> names = get_node_names(*this);
std::string unique_name(name.c_str());
unique_layer_name(names, unique_name.data());
return group.add_layer_after(unique_name, layer);
}
blender::bke::greasepencil::Layer &GreasePencil::add_layer(const blender::StringRefNull name)
{
return this->add_layer(this->root_group.wrap(), name);
}
const blender::bke::greasepencil::Layer *GreasePencil::find_layer_by_name(
@ -1164,6 +1283,55 @@ blender::bke::greasepencil::Layer *GreasePencil::find_layer_by_name(
return this->root_group.wrap().find_layer_by_name(name);
}
void GreasePencil::rename_layer(blender::bke::greasepencil::Layer &layer,
blender::StringRefNull new_name)
{
using namespace blender;
if (layer.name() == new_name) {
return;
}
VectorSet<StringRefNull> names = get_node_names(*this);
std::string unique_name(new_name.c_str());
unique_layer_name(names, unique_name.data());
layer.set_name(unique_name);
}
void GreasePencil::remove_layer(blender::bke::greasepencil::Layer &layer)
{
using namespace blender::bke::greasepencil;
/* If the layer is active, update the active layer. */
const Layer *active_layer = this->get_active_layer();
if (active_layer == &layer) {
Span<const Layer *> layers = this->layers();
/* If there is no other layer available , unset the active layer. */
if (layers.size() == 1) {
this->set_active_layer(nullptr);
}
else {
/* Make the layer below active (if possible). */
if (active_layer == layers.first()) {
this->set_active_layer(layers[1]);
}
else {
int64_t active_index = layers.first_index(active_layer);
this->set_active_layer(layers[active_index - 1]);
}
}
}
/* Unlink the layer from the parent group. */
layer.parent_group().unlink_layer(&layer);
/* Remove drawings. */
/* TODO: In the future this should only remove drawings when the user count hits zero. */
for (GreasePencilFrame frame : layer.frames_for_write().values()) {
this->remove_drawing(frame.drawing_index);
}
/* Delete the layer. */
MEM_delete(&layer);
}
void GreasePencil::print_layer_tree()
{
using namespace blender::bke::greasepencil;

View File

@ -235,7 +235,7 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
}
if ((gpl->flag & GP_LAYER_ACTIVE) != 0) {
grease_pencil.active_layer = static_cast<GreasePencilLayer *>(&new_layer);
grease_pencil.set_active_layer(&new_layer);
}
/* TODO: Update drawing user counts. */

View File

@ -24,6 +24,7 @@ set(INC_SYS
set(SRC
intern/grease_pencil_add.cc
intern/grease_pencil_edit.cc
intern/grease_pencil_layers.cc
intern/grease_pencil_ops.cc
intern/grease_pencil_select.cc
)

View File

@ -1200,7 +1200,7 @@ void create_blank(Main &bmain, Object &object, const int frame_number)
object.actcol = material_index + 1;
Layer &new_layer = grease_pencil.add_layer(grease_pencil.root_group.wrap(), "GP_Layer");
grease_pencil.active_layer = &new_layer;
grease_pencil.set_active_layer(&new_layer);
grease_pencil.add_empty_drawings(1);
@ -1224,7 +1224,7 @@ void create_stroke(Main &bmain, Object &object, float4x4 matrix, const int frame
Layer &layer_lines = grease_pencil.add_layer(grease_pencil.root_group.wrap(), "Lines");
Layer &layer_color = grease_pencil.add_layer(grease_pencil.root_group.wrap(), "Color");
grease_pencil.active_layer = &layer_lines;
grease_pencil.set_active_layer(&layer_lines);
grease_pencil.add_empty_drawings(2);
@ -1289,7 +1289,7 @@ void create_suzanne(Main &bmain, Object &object, float4x4 matrix, const int fram
Layer &layer_fills = grease_pencil.add_layer(grease_pencil.root_group.wrap(), "Fills");
Layer &layer_lines = grease_pencil.add_layer(grease_pencil.root_group.wrap(), "Lines");
grease_pencil.active_layer = &layer_lines;
grease_pencil.set_active_layer(&layer_lines);
grease_pencil.add_empty_drawings(2);

View File

@ -15,6 +15,15 @@
namespace blender::ed::greasepencil {
bool active_grease_pencil_poll(bContext *C)
{
Object *object = CTX_data_active_object(C);
if (object == nullptr || object->type != OB_GREASE_PENCIL) {
return false;
}
return true;
}
bool editable_grease_pencil_poll(bContext *C)
{
Object *object = CTX_data_active_object(C);

View File

@ -0,0 +1,107 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edgreasepencil
*/
#include "BKE_context.h"
#include "BKE_grease_pencil.hh"
#include "DEG_depsgraph.h"
#include "ED_grease_pencil.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
namespace blender::ed::greasepencil {
static int grease_pencil_layer_add_exec(bContext *C, wmOperator *op)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
int new_layer_name_length;
char *new_layer_name = RNA_string_get_alloc(
op->ptr, "new_layer_name", nullptr, 0, &new_layer_name_length);
if (grease_pencil.has_active_layer()) {
LayerGroup &active_group = grease_pencil.get_active_layer()->parent_group();
Layer &new_layer = grease_pencil.add_layer_after(
active_group, grease_pencil.get_active_layer_for_write(), new_layer_name);
grease_pencil.set_active_layer(&new_layer);
}
else {
Layer &new_layer = grease_pencil.add_layer(new_layer_name);
grease_pencil.set_active_layer(&new_layer);
}
MEM_SAFE_FREE(new_layer_name);
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_layer_add(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Add New Layer";
ot->idname = "GREASE_PENCIL_OT_layer_add";
ot->description = "Add new a new Grease Pencil layer in the active object";
/* callbacks */
ot->exec = grease_pencil_layer_add_exec;
ot->poll = editable_grease_pencil_poll;
prop = RNA_def_string(
ot->srna, "new_layer_name", "GP_Layer", INT16_MAX, "Name", "Name of the new layer");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = prop;
}
static int grease_pencil_layer_remove_exec(bContext *C, wmOperator * /*op*/)
{
using namespace blender::bke::greasepencil;
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (!grease_pencil.has_active_layer()) {
return OPERATOR_CANCELLED;
}
grease_pencil.remove_layer(*grease_pencil.get_active_layer_for_write());
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_layer_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Layer";
ot->idname = "GREASE_PENCIL_OT_layer_remove";
ot->description = "Remove the active Grease Pencil layer";
/* callbacks */
ot->exec = grease_pencil_layer_remove_exec;
ot->poll = editable_grease_pencil_poll;
}
} // namespace blender::ed::greasepencil
void ED_operatortypes_grease_pencil_layers(void)
{
using namespace blender::ed::greasepencil;
WM_operatortype_append(GREASE_PENCIL_OT_layer_add);
WM_operatortype_append(GREASE_PENCIL_OT_layer_remove);
}

View File

@ -10,6 +10,7 @@
void ED_operatortypes_grease_pencil(void)
{
ED_operatortypes_grease_pencil_select();
ED_operatortypes_grease_pencil_draw();
ED_operatortypes_grease_pencil_layers();
ED_operatortypes_grease_pencil_select();
}

View File

@ -27,6 +27,7 @@ extern "C" {
void ED_operatortypes_grease_pencil(void);
void ED_operatortypes_grease_pencil_draw(void);
void ED_operatortypes_grease_pencil_layers(void);
void ED_operatortypes_grease_pencil_select(void);
void ED_keymap_grease_pencil(struct wmKeyConfig *keyconf);
/**
@ -44,6 +45,7 @@ eAttrDomain ED_grease_pencil_selection_domain_get(struct bContext *C);
namespace blender::ed::greasepencil {
bool active_grease_pencil_poll(bContext *C);
bool editable_grease_pencil_poll(bContext *C);
bool editable_grease_pencil_point_selection_poll(bContext *C);

View File

@ -2630,6 +2630,8 @@ void uiTemplateLightLinkingCollection(struct uiLayout *layout,
struct PointerRNA *ptr,
const char *propname);
void uiTemplateGreasePencilLayerTree(uiLayout *layout, struct bContext *C);
/**
* \return: A RNA pointer for the operator properties.
*/

View File

@ -70,6 +70,7 @@ set(SRC
interface_template_asset_view.cc
interface_template_attribute_search.cc
interface_template_light_linking.cc
interface_template_grease_pencil_layer_tree.cc
interface_template_list.cc
interface_template_search_menu.cc
interface_template_search_operator.cc

View File

@ -0,0 +1,150 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edinterface
*/
#include "BKE_context.h"
#include "BKE_grease_pencil.hh"
#include "BLT_translation.h"
#include "UI_interface.h"
#include "UI_interface.hh"
#include "UI_tree_view.hh"
namespace blender::ui::greasepencil {
using namespace blender::bke::greasepencil;
class LayerViewItem : public AbstractTreeViewItem {
public:
LayerViewItem(GreasePencil &grease_pencil, Layer &layer)
: grease_pencil_(grease_pencil), layer_(layer)
{
this->label_ = layer.name();
}
void build_row(uiLayout &row) override
{
uiLayout *sub = uiLayoutRow(&row, true);
uiItemL(sub, IFACE_(layer_.name().c_str()), ICON_GREASEPENCIL);
}
bool supports_collapsing() const
{
return false;
}
std::optional<bool> should_be_active() const override
{
if (this->grease_pencil_.has_active_layer()) {
return reinterpret_cast<GreasePencilLayer *>(&layer_) == this->grease_pencil_.active_layer;
}
return {};
}
void on_activate()
{
this->grease_pencil_.set_active_layer(&layer_);
}
bool supports_renaming() const override
{
return true;
}
bool rename(StringRefNull new_name) override
{
grease_pencil_.rename_layer(layer_, new_name);
return true;
}
StringRef get_rename_string() const override
{
return layer_.name();
}
private:
GreasePencil &grease_pencil_;
Layer &layer_;
};
class LayerGroupViewItem : public AbstractTreeViewItem {
public:
LayerGroupViewItem(GreasePencil &grease_pencil, LayerGroup &group)
: grease_pencil_(grease_pencil), group_(group)
{
this->label_ = group_.name();
}
void build_row(uiLayout &row) override
{
uiLayout *sub = uiLayoutRow(&row, true);
uiItemL(sub, IFACE_(group_.name().c_str()), ICON_FILE_FOLDER);
}
private:
GreasePencil &grease_pencil_;
LayerGroup &group_;
};
class LayerTreeView : public AbstractTreeView {
public:
explicit LayerTreeView(GreasePencil &grease_pencil) : grease_pencil_(grease_pencil) {}
void build_tree() override;
private:
void build_tree_node_recursive(TreeNode &node);
GreasePencil &grease_pencil_;
};
void LayerTreeView::build_tree_node_recursive(TreeNode &node)
{
using namespace blender::bke::greasepencil;
if (node.is_layer()) {
add_tree_item<LayerViewItem>(this->grease_pencil_, node.as_layer_for_write());
}
else if (node.is_group()) {
add_tree_item<LayerGroupViewItem>(this->grease_pencil_, node.as_group_for_write());
LISTBASE_FOREACH_BACKWARD (GreasePencilLayerTreeNode *, node_, &node.as_group().children) {
build_tree_node_recursive(node_->wrap());
}
}
}
void LayerTreeView::build_tree()
{
using namespace blender::bke::greasepencil;
LISTBASE_FOREACH_BACKWARD (
GreasePencilLayerTreeNode *, node, &this->grease_pencil_.root_group.children)
{
this->build_tree_node_recursive(node->wrap());
}
}
} // namespace blender::ui::greasepencil
void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C)
{
using namespace blender;
Object *object = CTX_data_active_object(C);
if (!object || object->type != OB_GREASE_PENCIL) {
return;
}
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
uiBlock *block = uiLayoutGetBlock(layout);
ui::AbstractTreeView *tree_view = UI_block_add_view(
*block,
"Grease Pencil Layer Tree View",
std::make_unique<blender::ui::greasepencil::LayerTreeView>(grease_pencil));
tree_view->set_min_rows(3);
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
}

View File

@ -58,7 +58,7 @@ struct PaintOperationExecutor {
BLI_assert_unreachable();
// grease_pencil.runtime->set_active_layer_index(0);
}
const bke::greasepencil::Layer &active_layer = grease_pencil.active_layer->wrap();
const bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
int index = active_layer.drawing_index_at(scene->r.cfra);
BLI_assert(index != -1);
@ -95,8 +95,8 @@ void PaintOperation::on_stroke_done(const bContext &C)
GreasePencil &grease_pencil_orig = *static_cast<GreasePencil *>(obact->data);
GreasePencil &grease_pencil_eval = *static_cast<GreasePencil *>(ob_eval->data);
BLI_assert(grease_pencil_orig.has_active_layer() && grease_pencil_eval.has_active_layer());
const bke::greasepencil::Layer &active_layer_orig = grease_pencil_orig.active_layer->wrap();
const bke::greasepencil::Layer &active_layer_eval = grease_pencil_eval.active_layer->wrap();
const bke::greasepencil::Layer &active_layer_orig = *grease_pencil_orig.get_active_layer();
const bke::greasepencil::Layer &active_layer_eval = *grease_pencil_eval.get_active_layer();
int index_orig = active_layer_orig.drawing_index_at(scene->r.cfra);
int index_eval = active_layer_eval.drawing_index_at(scene->r.cfra);
BLI_assert(index_orig != -1 && index_eval != -1);

View File

@ -262,6 +262,9 @@ static bool buttons_context_path_data(ButsContextPath *path, int type)
if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && ELEM(type, -1, OB_GPENCIL_LEGACY)) {
return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_GreasePencilv3) && ELEM(type, -1, OB_GREASE_PENCIL)) {
return true;
}
if (RNA_struct_is_a(ptr->type, &RNA_Curves) && ELEM(type, -1, OB_CURVES)) {
return true;
}
@ -301,6 +304,7 @@ static bool buttons_context_path_modifier(ButsContextPath *path)
OB_SURF,
OB_LATTICE,
OB_GPENCIL_LEGACY,
OB_GREASE_PENCIL,
OB_CURVES,
OB_POINTCLOUD,
OB_VOLUME))
@ -838,6 +842,7 @@ const char *buttons_context_dir[] = {
"line_style",
"collection",
"gpencil",
"grease_pencil",
"curves",
#ifdef WITH_POINT_CLOUD
"pointcloud",
@ -1165,6 +1170,10 @@ int /*eContextResult*/ buttons_context(const bContext *C,
set_pointer_type(path, result, &RNA_GreasePencil);
return CTX_RESULT_OK;
}
if (CTX_data_equals(member, "grease_pencil")) {
set_pointer_type(path, result, &RNA_GreasePencilv3);
return CTX_RESULT_OK;
}
return CTX_RESULT_MEMBER_NOT_FOUND;
}

View File

@ -443,13 +443,27 @@ typedef struct GreasePencil {
blender::Span<const blender::bke::greasepencil::Layer *> layers() const;
blender::Span<blender::bke::greasepencil::Layer *> layers_for_write();
blender::Span<const blender::bke::greasepencil::TreeNode *> nodes() const;
bool has_active_layer() const;
const blender::bke::greasepencil::Layer *get_active_layer() const;
blender::bke::greasepencil::Layer *get_active_layer_for_write();
void set_active_layer(const blender::bke::greasepencil::Layer *layer);
blender::bke::greasepencil::Layer &add_layer(blender::bke::greasepencil::LayerGroup &group,
blender::StringRefNull name);
blender::bke::greasepencil::Layer &add_layer(blender::StringRefNull name);
blender::bke::greasepencil::Layer &add_layer_after(blender::bke::greasepencil::LayerGroup &group,
blender::bke::greasepencil::Layer *layer,
blender::StringRefNull name);
const blender::bke::greasepencil::Layer *find_layer_by_name(blender::StringRefNull name) const;
blender::bke::greasepencil::Layer *find_layer_by_name(blender::StringRefNull name);
void rename_layer(blender::bke::greasepencil::Layer &layer, blender::StringRefNull new_name);
void remove_layer(blender::bke::greasepencil::Layer &layer);
void add_empty_drawings(int add_num);
void remove_drawing(int index);

View File

@ -1981,6 +1981,11 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_ui_description(func,
"Visualization of a content of a light linking collection");
api_ui_item_rna_common(func);
func = RNA_def_function(
srna, "template_grease_pencil_layer_tree", "uiTemplateGreasePencilLayerTree");
RNA_def_function_ui_description(func, "View of the active grease pencil layer tree");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
}
#endif