GPv3: Keyframe on-click selection
Implementation of the click-selection operator of keyframes in the dopesheet, along with its alternatives : deselect all when no frames is hit, extend selection with shift, column selection with alt, select all keyframes on current channel with ctrl+alt. Includes the new following API functions : * `select_frame_at` : selects a frame in a layer at a specific time (if such frame exists), * `select_all_frames` : selects all frames of a layer, * `select_layer_channel` : selects a layer, and sets it as active (if layer is not null, otherwise the active layer is set null), * `layer_has_frame_selected` : checks if any of the frames in the layer is selected. Pull Request: https://projects.blender.org/blender/blender/pulls/110492
This commit is contained in:
committed by
Falk David
parent
0fab1f4f68
commit
0c07fb50c8
@@ -499,6 +499,11 @@ inline bool GreasePencilFrame::is_implicit_hold() const
|
||||
return (this->flag & GP_FRAME_IMPLICIT_HOLD) != 0;
|
||||
}
|
||||
|
||||
inline bool GreasePencilFrame::is_selected() const
|
||||
{
|
||||
return (this->flag & GP_FRAME_SELECTED) != 0;
|
||||
}
|
||||
|
||||
inline blender::bke::greasepencil::TreeNode &GreasePencilLayerTreeNode::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::bke::greasepencil::TreeNode *>(this);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mask.h"
|
||||
@@ -593,6 +594,12 @@ static void anim_channels_select_set(bAnimContext *ac,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GREASE_PENCIL_LAYER: {
|
||||
using namespace blender::bke::greasepencil;
|
||||
Layer *layer = static_cast<Layer *>(ale->data);
|
||||
ACHANNEL_SET_FLAG(&(layer->base), sel, GP_LAYER_TREE_NODE_SELECT);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GPLAYER: {
|
||||
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||
|
||||
|
||||
@@ -1872,12 +1872,12 @@ static size_t animdata_filter_grease_pencil_data(ListBase *anim_data,
|
||||
/* Add data block container (if for drawing, and it contains sub-channels). */
|
||||
ANIMCHANNEL_NEW_CHANNEL(
|
||||
grease_pencil, ANIMTYPE_GREASE_PENCIL_DATABLOCK, grease_pencil, nullptr);
|
||||
|
||||
/* Add the list of collected channels. */
|
||||
BLI_movelisttolist(anim_data, &tmp_data);
|
||||
BLI_assert(BLI_listbase_is_empty(&tmp_data));
|
||||
items += tmp_items;
|
||||
}
|
||||
|
||||
/* Add the list of collected channels. */
|
||||
BLI_movelisttolist(anim_data, &tmp_data);
|
||||
BLI_assert(BLI_listbase_is_empty(&tmp_data));
|
||||
items += tmp_items;
|
||||
}
|
||||
|
||||
return items;
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* \ingroup edgreasepencil
|
||||
*/
|
||||
|
||||
#include "BLI_map.hh"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
|
||||
@@ -14,6 +16,7 @@
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "ED_grease_pencil.h"
|
||||
#include "ED_keyframes_edit.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
@@ -22,6 +25,52 @@
|
||||
|
||||
namespace blender::ed::greasepencil {
|
||||
|
||||
static void select_frame(GreasePencilFrame &frame, const short select_mode)
|
||||
{
|
||||
switch (select_mode) {
|
||||
case SELECT_ADD:
|
||||
frame.flag |= GP_FRAME_SELECTED;
|
||||
break;
|
||||
case SELECT_SUBTRACT:
|
||||
frame.flag &= ~GP_FRAME_SELECTED;
|
||||
break;
|
||||
case SELECT_INVERT:
|
||||
frame.flag ^= GP_FRAME_SELECTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool select_frame_at(bke::greasepencil::Layer *layer,
|
||||
const int frame_number,
|
||||
const short select_mode)
|
||||
{
|
||||
|
||||
GreasePencilFrame *frame = layer->frames_for_write().lookup_ptr(frame_number);
|
||||
if (frame == nullptr) {
|
||||
return false;
|
||||
}
|
||||
select_frame(*frame, select_mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
void select_all_frames(bke::greasepencil::Layer *layer, const short select_mode)
|
||||
{
|
||||
for (auto item : layer->frames_for_write().items()) {
|
||||
select_frame(item.value, select_mode);
|
||||
}
|
||||
}
|
||||
|
||||
bool layer_has_any_frame_selected(const bke::greasepencil::Layer *layer)
|
||||
{
|
||||
for (auto item : layer->frames().items()) {
|
||||
const GreasePencilFrame &frame = item.value;
|
||||
if (frame.is_selected()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int insert_blank_frame_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
@@ -22,6 +22,20 @@
|
||||
|
||||
namespace blender::ed::greasepencil {
|
||||
|
||||
void select_layer_channel(GreasePencil *grease_pencil, bke::greasepencil::Layer *layer)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
if (layer != nullptr) {
|
||||
layer->base.flag |= GP_LAYER_TREE_NODE_SELECT;
|
||||
}
|
||||
|
||||
if (grease_pencil->active_layer != layer) {
|
||||
grease_pencil->set_active_layer(layer);
|
||||
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, &grease_pencil);
|
||||
}
|
||||
}
|
||||
|
||||
static int grease_pencil_layer_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
@@ -50,11 +50,30 @@ eAttrDomain ED_grease_pencil_selection_domain_get(struct bContext *C);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include "BKE_grease_pencil.hh"
|
||||
|
||||
# include "BLI_generic_span.hh"
|
||||
# include "BLI_math_matrix_types.hh"
|
||||
|
||||
namespace blender::ed::greasepencil {
|
||||
|
||||
void select_layer_channel(GreasePencil *grease_pencil, bke::greasepencil::Layer *layer);
|
||||
|
||||
/**
|
||||
* Sets the selection flag, according to \a selection_mode to the frame at \a frame_number in the
|
||||
* \a layer if such frame exists. Returns false if no such frame exists.
|
||||
*/
|
||||
bool select_frame_at(bke::greasepencil::Layer *layer,
|
||||
const int frame_number,
|
||||
const short select_mode);
|
||||
|
||||
void select_all_frames(bke::greasepencil::Layer *layer, const short select_mode);
|
||||
|
||||
/**
|
||||
* Returns true if any frame of the \a layer is selected.
|
||||
*/
|
||||
bool layer_has_any_frame_selected(const bke::greasepencil::Layer *layer);
|
||||
|
||||
bool active_grease_pencil_poll(bContext *C);
|
||||
bool editable_grease_pencil_poll(bContext *C);
|
||||
bool editable_grease_pencil_point_selection_poll(bContext *C);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_gpencil_legacy.h"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_nla.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
@@ -37,6 +38,7 @@
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_gpencil_legacy.h"
|
||||
#include "ED_grease_pencil.h"
|
||||
#include "ED_keyframes_edit.h"
|
||||
#include "ED_keyframes_keylist.h"
|
||||
#include "ED_markers.h"
|
||||
@@ -129,6 +131,11 @@ static void actkeys_list_element_to_keylist(bAnimContext *ac,
|
||||
bActionGroup *agrp = (bActionGroup *)ale->data;
|
||||
agroup_to_keylist(adt, agrp, keylist, 0);
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
/* TODO: why don't we just give grease pencil layers key_data too? */
|
||||
grease_pencil_cels_to_keylist(
|
||||
adt, static_cast<blender::bke::greasepencil::Layer *>(ale->data), keylist, 0);
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GPLAYER) {
|
||||
/* TODO: why don't we just give gplayers key_data too? */
|
||||
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||
@@ -273,6 +280,14 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
if (blender::ed::greasepencil::layer_has_any_frame_selected(
|
||||
static_cast<blender::bke::greasepencil::Layer *>(ale->data)))
|
||||
{
|
||||
sel = SELECT_SUBTRACT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (ANIM_fcurve_keyframes_loop(
|
||||
&ked, static_cast<FCurve *>(ale->key_data), nullptr, test_cb, nullptr))
|
||||
@@ -296,6 +311,11 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
|
||||
else if (ale->type == ANIMTYPE_MASKLAYER) {
|
||||
ED_masklayer_frame_select_set(static_cast<MaskLayer *>(ale->data), sel);
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
blender::ed::greasepencil::select_all_frames(
|
||||
static_cast<blender::bke::greasepencil::Layer *>(ale->data), sel);
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
}
|
||||
else {
|
||||
ANIM_fcurve_keyframes_loop(
|
||||
&ked, static_cast<FCurve *>(ale->key_data), nullptr, sel_cb, nullptr);
|
||||
@@ -1627,6 +1647,11 @@ static void actkeys_mselect_single(bAnimContext *ac,
|
||||
ED_gpencil_select_frame(static_cast<bGPDlayer *>(ale->data), selx, select_mode);
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
blender::ed::greasepencil::select_frame_at(
|
||||
static_cast<blender::bke::greasepencil::Layer *>(ale->data), selx, select_mode);
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_MASKLAYER) {
|
||||
ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
|
||||
}
|
||||
@@ -1692,6 +1717,11 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
|
||||
else if (ale->type == ANIMTYPE_MASKLAYER) {
|
||||
ED_mask_select_frame(static_cast<MaskLayer *>(ale->data), selx, select_mode);
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
blender::ed::greasepencil::select_frame_at(
|
||||
static_cast<blender::bke::greasepencil::Layer *>(ale->data), selx, select_mode);
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
}
|
||||
else {
|
||||
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
||||
|
||||
@@ -1731,6 +1761,11 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
|
||||
else if (ale->type == ANIMTYPE_MASKLAYER) {
|
||||
ED_mask_select_frames(static_cast<MaskLayer *>(ale->data), select_mode);
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
blender::ed::greasepencil::select_all_frames(
|
||||
static_cast<blender::bke::greasepencil::Layer *>(ale->data), select_mode);
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
}
|
||||
else {
|
||||
if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
|
||||
ListBase anim_data = {nullptr, nullptr};
|
||||
@@ -1836,10 +1871,17 @@ static int mouse_action_keys(bAnimContext *ac,
|
||||
}
|
||||
}
|
||||
else if (ac->datatype == ANIMCONT_GPENCIL) {
|
||||
/* deselect all other channels first */
|
||||
/* Deselect all other channels first. */
|
||||
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
|
||||
|
||||
/* Highlight GPencil Layer */
|
||||
/* Highlight the grease pencil channel, and set the corresponding layer as active. */
|
||||
if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
using namespace blender::bke::greasepencil;
|
||||
blender::ed::greasepencil::select_layer_channel(
|
||||
reinterpret_cast<GreasePencil *>(ale->id), static_cast<Layer *>(ale->data));
|
||||
}
|
||||
|
||||
/* Highlight GPencil Layer (Legacy). */
|
||||
if (ale != nullptr && ale->data != nullptr && ale->type == ANIMTYPE_GPLAYER) {
|
||||
bGPdata *gpd = (bGPdata *)ale->id;
|
||||
bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
|
||||
|
||||
@@ -367,6 +367,9 @@ static void createTransActionData(bContext *C, TransInfo *t)
|
||||
adt_count = count_gplayer_frames(
|
||||
static_cast<bGPDlayer *>(ale->data), t->frame_side, cfra, is_prop_edit);
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) {
|
||||
/* GPv3: To be implemented. */
|
||||
}
|
||||
else if (ale->type == ANIMTYPE_MASKLAYER) {
|
||||
adt_count = count_masklayer_frames(
|
||||
static_cast<MaskLayer *>(ale->data), t->frame_side, cfra, is_prop_edit);
|
||||
|
||||
@@ -156,6 +156,7 @@ typedef struct GreasePencilFrame {
|
||||
static GreasePencilFrame null();
|
||||
bool is_null() const;
|
||||
bool is_implicit_hold() const;
|
||||
bool is_selected() const;
|
||||
#endif
|
||||
} GreasePencilFrame;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user