Skip to main content
New Participant
May 21, 2024

UI params do not update correctly when using the timeline ruler with a left click.

  • May 21, 2024
  • 5 replies
  • 531 views

Version: Adobe After Effects version 23.6.5

 

System: Microsoft Windows 11 Pro.

 

Steps to reproduce the problem: this can be reproduced using the attached entry_point file or using the AE's builtin Channel Combiner effect. I will describe the steps to reproduce the problem using the Channel Combiner effect.

- Create a composition with an image

- Add the Channel Combiner effect to it

- Check the parameter Source Options > Use 2nd Layer parameter and add a keyframe at time 00s. Note that the parameter Source Options > Source Layer is now enabled (not grayed out).

- Go to another time (for example 02s) and uncheck the parameter Source Options > Use 2nd Layer. Note that the parameter Source Options > Source Layer is now disabled (grayed out).

- Using the timeline ruler, set the current time to 00s with a left click.

Expected result:  Source Options > Use 2nd Layer is checked and Source Options > Source Layer is enabled.

Actual result:  Source Options > Use 2nd Layer is checked but Source Options > Source Layer is disabled (grayed out).

 

Optional informations:

I also created a minimal effect plugin and I noticed while debugging that changing the current time using the timeline ruler does not trigger the entry_point function therefore no PF_Cmd_UPDATE_PARAMS_UI is sent.

I also tried an empty cache approach and still does not work.

 

#include <AEFX_SuiteHandlerTemplate.h>
#include <AE_EffectCBSuites.h>
#include <AEGP_SuiteHandler.h>

#include <cassert>
#include <stdexcept>
#include <string>

//
// Minimal example with two boolean parameters: Param 1 and Param 2.
// The effect simply copies input to output.
//
// How to reproduce the problem:
// - Add the effect to a composition.
// - Add a keyframe on effect's Param 1 (unchecked).
// - Change the current time to a different time and set Param 1 to checked. Param 2 is now disabled/grayed out.
// - Click on the timeline ruler on param1's first key (where param 1 is not checked).
// - Now param 1 is not checked but param 2 is still disabled/grayed out.
//

namespace
{
const int param_input_layer_id = 0;
const int param_param_1_id = 1;
const int param_param_2_id = 2;

bool is_empty(const PF_LRect* r)
{
return (r->left >= r->right) || (r->top >= r->bottom);
}

void union_rect(const PF_LRect* src, PF_LRect* dst)
{
if (is_empty(dst)) {
*dst = *src;
}
else if (!is_empty(src)) {
dst->left = std::min(dst->left, src->left);
dst->top = std::min(dst->top, src->top);
dst->right = std::max(dst->right, src->right);
dst->bottom = std::max(dst->bottom, src->bottom);
}
}

void clear_param_def(PF_ParamDef& def)
{
A_long _t = sizeof(def);
A_char* _p = (A_char*)&(def);
while (_t--) {
*_p++ = 0;
}
}

void throw_if_err(PF_Err err)
{
if (err != PF_Err_NONE) {
throw std::runtime_error(std::to_string(err));
}
}

bool get_checkbox_value(PF_InData* in_data, PF_ParamIndex index)
{
PF_ParamDef def;
clear_param_def(def);
throw_if_err(in_data->inter.checkout_param(
in_data->effect_ref,
index,
in_data->current_time,
in_data->time_step,
in_data->time_scale,
&def));

assert(def.param_type == PF_Param_CHECKBOX);
bool value = def.u.bd.value;

throw_if_err(in_data->inter.checkin_param(in_data->effect_ref, &def));

return value;
}
}

PF_Err entry_point(
PF_Cmd cmd,
PF_InData* in_data,
PF_OutData* out_data,
PF_ParamDef* params[],
PF_LayerDef* output,
void* extra)
{
PF_Err err = PF_Err_NONE;
try {
switch (cmd) {
case PF_Cmd_GLOBAL_SETUP:
{
const int major_version = 1;
const int minor_version = 1;
const char* name = "my effect";

out_data->my_version = (major_version * 524288 + minor_version * 32768 + 0 * 2048 + 0 * 512);

out_data->out_flags =
PF_OutFlag_DEEP_COLOR_AWARE |
PF_OutFlag_USE_OUTPUT_EXTENT |
PF_OutFlag_SEND_UPDATE_PARAMS_UI |
PF_OutFlag_PIX_INDEPENDENT;

out_data->out_flags2 =
PF_OutFlag2_SUPPORTS_SMART_RENDER |
PF_OutFlag2_FLOAT_COLOR_AWARE |
PF_OutFlag2_SUPPORTS_THREADED_RENDERING;

AEFX_SuiteScoper<AEGP_UtilitySuite6> utilitySuite(in_data, kAEGPUtilitySuite, kAEGPUtilitySuiteVersion6);
AEGP_PluginID aegp_plugin_id;
throw_if_err(utilitySuite->AEGP_RegisterWithAEGP(nullptr, name, &aegp_plugin_id));

break;
}
case PF_Cmd_GLOBAL_SETDOWN:
{
break;
}
case PF_Cmd_ABOUT:
{
break;
}
case PF_Cmd_PARAMS_SETUP:
{
{
PF_ParamDef def;
clear_param_def(def);

const char* param_name = "Param 1";

def.param_type = PF_Param_CHECKBOX;
def.u.bd.u.nameptr = param_name;
def.u.bd.value = false;
def.u.bd.dephault = (PF_Boolean)(def.u.bd.value);

in_data->utils->ansi.strcpy(def.name, param_name);
def.uu.id = param_param_1_id;
def.flags = PF_ParamFlag_SUPERVISE;
def.ui_flags = PF_ParamUIFlags();

throw_if_err(in_data->inter.add_param(in_data->effect_ref, -1, &def));
}

{
PF_ParamDef def;
clear_param_def(def);

const char* param_name = "Param 2";

def.param_type = PF_Param_CHECKBOX;
def.u.bd.u.nameptr = param_name;
def.u.bd.value = false;
def.u.bd.dephault = (PF_Boolean)(def.u.bd.value);

in_data->utils->ansi.strcpy(def.name, param_name);
def.uu.id = param_param_2_id;
def.flags = PF_ParamFlag_SUPERVISE;
def.ui_flags = PF_ParamUIFlags();

throw_if_err(in_data->inter.add_param(in_data->effect_ref, -1, &def));
}

// Layer + param 1 + param 2
out_data->num_params = 3;

break;
}
case PF_Cmd_SEQUENCE_SETUP:
{
break;
}
case PF_Cmd_SEQUENCE_SETDOWN:
{
break;
}
case PF_Cmd_SEQUENCE_RESETUP:// is sent when a project is loaded or when the layer to which it fs applied changes.
{
break;
}
case PF_Cmd_SEQUENCE_FLATTEN://PF_Cmd_SEQUENCE_FLATTEN is sent when the After Effects project is written out to disk.
{
break;
}
case PF_Cmd_GET_FLATTENED_SEQUENCE_DATA:
{
break;
}
case PF_Cmd_FRAME_SETUP:
{
break;
}
case PF_Cmd_FRAME_SETDOWN:
{
break;
}
case PF_Cmd_GPU_DEVICE_SETUP:
{
break;
}
case PF_Cmd_GPU_DEVICE_SETDOWN:
{
break;
}
case PF_Cmd_RENDER:
{
break;
}
case PF_Cmd_SMART_PRE_RENDER:
{
PF_PreRenderExtra* pre_render_extra = reinterpret_cast<PF_PreRenderExtra*>(extra);

PF_RenderRequest req = pre_render_extra->input->output_request;

PF_CheckoutResult in_result;
throw_if_err(pre_render_extra->cb->checkout_layer(
in_data->effect_ref,
param_input_layer_id,
param_input_layer_id,
&req,
in_data->current_time,
in_data->time_step,
in_data->time_scale,
&in_result));

union_rect(&in_result.result_rect, &pre_render_extra->output->result_rect);
union_rect(&in_result.max_result_rect, &pre_render_extra->output->max_result_rect);

break;
}
case PF_Cmd_SMART_RENDER:
{
PF_SmartRenderExtra* smart_render_extra = reinterpret_cast<PF_SmartRenderExtra*>(extra);

PF_EffectWorld* input = nullptr;
PF_EffectWorld* output = nullptr;
throw_if_err(smart_render_extra->cb->checkout_layer_pixels(in_data->effect_ref, param_input_layer_id, &input));
throw_if_err(smart_render_extra->cb->checkout_output(in_data->effect_ref, &output));
assert(input);
assert(output);

A_long linesS = output->extent_hint.bottom - output->extent_hint.top;
throw_if_err(in_data->utils->copy(in_data->effect_ref, input, output, nullptr, nullptr));

break;
}
case PF_Cmd_SMART_RENDER_GPU:/* used when rendering on the GPU */
{
break;
}

case PF_Cmd_USER_CHANGED_PARAM:/* change param value according to other parameter change */
{
break;
}
case PF_Cmd_UPDATE_PARAMS_UI:/* UI fields in paramdefs need to be refreshed according to new values */
{
// Param 1 value.
bool param_1 = get_checkbox_value(in_data, param_param_1_id);

// Disable param 2.
{
PF_ParamDef def = *params[param_param_2_id];
if (param_1) {
def.ui_flags |= PF_PUI_DISABLED;
}
else {
def.ui_flags &= ~PF_PUI_DISABLED;
}

AEFX_SuiteScoper<PF_ParamUtilsSuite3> param_util_suite(in_data, kPFParamUtilsSuite, kPFParamUtilsSuiteVersion3);
throw_if_err(param_util_suite->PF_UpdateParamUI(in_data->effect_ref, param_param_2_id, &def));
}

out_data->out_flags |= PF_OutFlag_REFRESH_UI;

break;
}
case PF_Cmd_DO_DIALOG:/* called after SEQUENCE_SETUP only if effect requests */
{
break;
}
case PF_Cmd_EVENT:/* handle some event. extra contains a ptr to a relevant structure */
{
break;
}
case PF_Cmd_GET_EXTERNAL_DEPENDENCIES: /* new in AE4.1: return text description of things like fonts, etc. in PF_ExtDependenciesExtra */
{
break;
}
case PF_Cmd_COMPLETELY_GENERAL:/* new in AE4.1: Used for completely general effect calls via AEGP, extra has the data sent through AEGP_EffectCallGeneric */
{
break;
}
case PF_Cmd_QUERY_DYNAMIC_FLAGS:
{
break;
}
case PF_Cmd_ARBITRARY_CALLBACK:/* used for arbitrary data, passes PF_ArbParamsExtra * in extra */
{
break;
}
case PF_Cmd_AUDIO_RENDER:/* For Audio Effects */
{
break;
}
case PF_Cmd_AUDIO_SETUP:
{
break;
}
case PF_Cmd_AUDIO_SETDOWN:
{
break;
}
}
}
catch (std::exception& ex) {
out_data->out_flags |= PF_OutFlag_DISPLAY_ERROR_MESSAGE;
in_data->utils->ansi.sprintf(out_data->return_msg, ex.what());
}
catch (...) {
out_data->out_flags |= PF_OutFlag_DISPLAY_ERROR_MESSAGE;
in_data->utils->ansi.sprintf(out_data->return_msg, "undefined exception occured");
}
return err;
}

 

5 replies

JohnColombo17100380
Community Manager
Community Manager
October 2, 2025

Hi @tanguyc6318348,

This issue was fixed in After Effects 24.6. Thanks very much for reporting this!

 

- John, After Effects Engineering Team  

Community Manager
July 10, 2024

The fix for this is now available in beta builds, starting with 24.6x47. @tanguyc6318348 can you try it out and see if things are resolved for you? Thanks.

Community Manager
June 10, 2024

Thanks for logging this. There has been a missing call to refresh the effect parameters/supervised parameters on the mouse click. We have a fix for that now in internal testing. I'll post back once it's available in Beta builds.

JohnColombo17100380
Community Manager
Community Manager
June 6, 2024

Per @nishu_kush's comment, marking thread as Investigating.

 

- John, After Effects Engineering Team  

nishu_kush
Community Manager
Community Manager
June 6, 2024

Thanks for bringing this up. We now have a ticket to investigate this.

 

Thanks,

Nishu