Skip to content

Commit

Permalink
undo: split the plugin interface (#421)
Browse files Browse the repository at this point in the history
* undo: split the plugin interface

* Fix compilation

* remove undo_state, it was unclear

* Doc.

* Doc.

* undo: set the rev to /4

* Doc.
  • Loading branch information
abique authored Sep 18, 2024
1 parent 1a8d91b commit 577e6dd
Showing 1 changed file with 40 additions and 11 deletions.
51 changes: 40 additions & 11 deletions include/clap/ext/draft/undo.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#pragma once

#include "../../plugin.h"
#include "../../stream.h"

static CLAP_CONSTEXPR const char CLAP_EXT_UNDO[] = "clap.undo/3";
static CLAP_CONSTEXPR const char CLAP_EXT_UNDO[] = "clap.undo/4";
static CLAP_CONSTEXPR const char CLAP_EXT_UNDO_CONTEXT[] = "clap.undo_context/4";
static CLAP_CONSTEXPR const char CLAP_EXT_UNDO_DELTA[] = "clap.undo_delta/4";

#ifdef __cplusplus
extern "C" {
Expand All @@ -15,7 +18,7 @@ extern "C" {
///
/// Calling host->undo() or host->redo() is equivalent to clicking undo/redo within the host's GUI.
///
/// If the plugin implements this interface then its undo and redo should be entirely delegated to
/// If the plugin uses this interface then its undo and redo should be entirely delegated to
/// the host; clicking in the plugin's UI undo or redo is equivalent to clicking undo or redo in the
/// host's UI.
///
Expand All @@ -40,6 +43,12 @@ extern "C" {
/// history. This simplifies the host implementation, leading to less bugs, a more robust design
/// and maybe an easier experience for the user because there's a single undo context versus one
/// for the host and one for each plugin instance.
///
/// This extension tries to make it as easy as possible for the plugin to hook into the host undo
/// and make it efficient when possible by using deltas. The plugin interfaces are all optional, and
/// the plugin can for a minimal implementation, just use the host interface and call
/// host->change_made() without providing a delta. This is enough for the host to know that it can
/// capture a plugin state for the undo step.

typedef struct clap_undo_delta_properties {
// If false, then all clap_undo_delta_properties's attributes become irrelevant.
Expand All @@ -54,7 +63,9 @@ typedef struct clap_undo_delta_properties {
uint32_t format_version;
} clap_undo_delta_properties_t;

typedef struct clap_plugin_undo {
// Use CLAP_EXT_UNDO_DELTA
// This is an optional interface, using deltas is an optimization versus making state snapshot.
typedef struct clap_plugin_undo_delta {
// Asks the plugin the delta properties.
// [main-thread]
void(CLAP_ABI *get_delta_properties)(const clap_plugin_t *plugin,
Expand Down Expand Up @@ -83,21 +94,26 @@ typedef struct clap_plugin_undo {
clap_id format_version,
const void *delta,
size_t delta_size);
} clap_plugin_undo_delta_t;

// Use CLAP_EXT_UNDO_CONTEXT
// This is an optional interface, that the plugin can implement in order to know about
// the current undo context.
typedef struct clap_plugin_undo_context {
// Indicate if it is currently possible to perform a redo or undo operation.
// if can_* is false then it invalidates the corresponding name.
// [main-thread]
void (CLAP_ABI *set_can_undo)(const clap_plugin_t *plugin, bool can_undo);
void (CLAP_ABI *set_can_redo)(const clap_plugin_t *plugin, bool can_redo);
void(CLAP_ABI *set_can_undo)(const clap_plugin_t *plugin, bool can_undo);
void(CLAP_ABI *set_can_redo)(const clap_plugin_t *plugin, bool can_redo);

// Sets the name of the next undo or redo step.
// name: null terminated string if an redo/undo step exists, null otherwise.
// name: null terminated string.
// [main-thread]
void (CLAP_ABI *set_undo_name)(const clap_plugin_t *plugin, const char *name);
void (CLAP_ABI *set_redo_name)(const clap_plugin_t *plugin, const char *name);

} clap_plugin_undo_t;
void(CLAP_ABI *set_undo_name)(const clap_plugin_t *plugin, const char *name);
void(CLAP_ABI *set_redo_name)(const clap_plugin_t *plugin, const char *name);
} clap_plugin_undo_context_t;

// Use CLAP_EXT_UNDO
typedef struct clap_host_undo {
// Begins a long running change.
// The plugin must not call this twice: there must be either a call to cancel_change() or
Expand All @@ -124,12 +140,23 @@ typedef struct clap_host_undo {
// plugin can indicate a format version id and the validity lifetime for the binary blobs.
// The host can use these to verify the compatibility before applying the delta.
// If the plugin is unable to use a delta, a notification should be provided to the user and
// the crash recovery should perform a best effort job, at least restoring the latest saved state.
// the crash recovery should perform a best effort job, at least restoring the latest saved
// state.
//
// Special case: for objects with shared and synchronized state, changes shouldn't be reported
// as the host already knows about it.
// For example, plugin parameter changes shouldn't produce a call to change_made().
//
// Note: if the plugin asked for this interface, then host_state->mark_dirty() will not create an
// implicit undo step.
//
// Note: if the plugin did load a preset or did something that leads to a large delta,
// it may consider not producing a delta (pass null) and let the host make a state snapshot
// instead.
//
// Note: if a plugin is producing a lot of changes within a small amount of time, the host
// may merge them into a single undo step.
//
// [main-thread]
void(CLAP_ABI *change_made)(const clap_host_t *host,
const char *name,
Expand All @@ -154,6 +181,8 @@ typedef struct clap_host_undo {
//
// is_subscribed: set to true to receive context info
//
// It is mandatory for the plugin to implement CLAP_EXT_UNDO_CONTEXT when using this method.
//
// [main-thread]
void(CLAP_ABI *set_wants_context_updates)(const clap_host_t *host, bool is_subscribed);
} clap_host_undo_t;
Expand Down

0 comments on commit 577e6dd

Please sign in to comment.