refactor(undo): switch oakundo to refcounted value handles, migrate consumers

- OakUndoCommand/OakUndoStack become neutral by-value handles
  {ctx, addref, release, abi_version}; a handle is a shared_ptr
  equivalent at the ABI level, internals untouched (box owns/observes
  flag; containers adopt, boxes created by factories own)
- oaknode command factories and undoable variants return/write value
  handles; timeline command classes hold value handles; task import
  take_command returns a value handle
- tests updated everywhere; suites green: oakundo 22, oaktimeline 117,
  oaktask 106, oaknode 96, oakrender 44, oakcodec 18, oakcommon 193,
  oakaudio 36
This commit is contained in:
2026-08-07 15:48:34 +08:00
parent da2ab512c6
commit 295ea1bfe5
41 changed files with 837 additions and 684 deletions
+1 -1
View File
@@ -84,7 +84,7 @@ OakNodeNode *oaknode_folder_as_node(OakNodeFolder *folder);
* @brief Create an undoable FolderAddChild command. Owned; free with
* oakundo_command_free().
*/
OakUndoCommand *oaknode_command_create_folder_add_child(
OakUndoCommand oaknode_command_create_folder_add_child(
OakNodeFolder *folder, OakNodeNode *child);
/**
+2 -2
View File
@@ -88,7 +88,7 @@ int oaknode_group_add_input_passthrough_undoable(OakNodeGroup *group,
OakNodeNode *node,
const char *input_id,
int element,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Remove the passthrough for (`node`, `input_id`, `element`)
@@ -137,7 +137,7 @@ int oaknode_group_set_output_passthrough(OakNodeGroup *group,
* (olive::NodeGroupSetOutputPassthrough).
*/
int oaknode_group_set_output_passthrough_undoable(
OakNodeGroup *group, OakNodeNode *node, OakUndoCommand **out_command);
OakNodeGroup *group, OakNodeNode *node, OakUndoCommand *out_command);
/**
* @brief Resolve an input through group passthroughs
+5 -5
View File
@@ -109,7 +109,7 @@ int oaknode_keyframe_set_time(OakNodeKeyframe *keyframe, int64_t time_num,
*/
int oaknode_keyframe_set_time_undoable(OakNodeKeyframe *keyframe,
int64_t time_num, int64_t time_den,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Read the keyframe's value mapped into `out`. Values without a
@@ -132,7 +132,7 @@ int oaknode_keyframe_set_value(OakNodeKeyframe *keyframe,
*/
int oaknode_keyframe_set_value_undoable(OakNodeKeyframe *keyframe,
const oaknode_value *v,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Read a string value. Two-stage getter.
@@ -154,7 +154,7 @@ int oaknode_keyframe_set_value_string(OakNodeKeyframe *keyframe,
*/
int oaknode_keyframe_set_value_string_undoable(OakNodeKeyframe *keyframe,
const char *value,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief The keyframe's interpolation type (oaknode_keyframe_type).
@@ -171,7 +171,7 @@ int oaknode_keyframe_set_type(OakNodeKeyframe *keyframe, int type);
* @brief Create a set-type command (same semantics as the live variant).
*/
int oaknode_keyframe_set_type_undoable(OakNodeKeyframe *keyframe, int type,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief A bezier control point (`handle` is an
@@ -192,7 +192,7 @@ int oaknode_keyframe_set_bezier_control(OakNodeKeyframe *keyframe, int handle,
*/
int oaknode_keyframe_set_bezier_control_undoable(OakNodeKeyframe *keyframe,
int handle, double x, double y,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief The keyframe's track index.
+13 -13
View File
@@ -171,7 +171,7 @@ int oaknode_node_set_label(OakNodeNode *node, const char *label);
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
*/
int oaknode_node_set_label_undoable(OakNodeNode *node, const char *label,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief The node's override color index (Node::get_override_color();
@@ -196,7 +196,7 @@ int oaknode_node_set_override_color(OakNodeNode *node, int index);
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
*/
int oaknode_node_set_override_color_undoable(OakNodeNode *node, int index,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief 1 if the node is enabled (the boolean "enabled_in" input's
@@ -220,7 +220,7 @@ int oaknode_node_set_enabled(OakNodeNode *node, int enabled);
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
*/
int oaknode_node_set_enabled_undoable(OakNodeNode *node, int enabled,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/* ---- Input introspection ------------------------------------------------ */
@@ -310,7 +310,7 @@ int oaknode_node_set_input(OakNodeNode *node, const char *input_id,
*/
int oaknode_node_set_input_undoable(OakNodeNode *node, const char *input_id,
const oaknode_value *v,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Read a string-family input's standard value. Two-stage getter.
@@ -331,7 +331,7 @@ int oaknode_node_set_input_string(OakNodeNode *node, const char *input_id,
int oaknode_node_set_input_string_undoable(OakNodeNode *node,
const char *input_id,
const char *value,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/* ---- Graph editing -------------------------------------------------------- */
@@ -356,7 +356,7 @@ int oaknode_node_connect(OakNodeNode *output_node, OakNodeNode *input_node,
int oaknode_node_connect_undoable(OakNodeNode *output_node,
OakNodeNode *input_node,
const char *input_id,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Remove the edge feeding `input_node`'s `input_id` directly
@@ -371,7 +371,7 @@ int oaknode_node_disconnect(OakNodeNode *input_node, const char *input_id);
*/
int oaknode_node_disconnect_undoable(OakNodeNode *input_node,
const char *input_id,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Number of outgoing edges (Node::output_connections()).
@@ -422,7 +422,7 @@ int oaknode_node_unlink(OakNodeNode *a, OakNodeNode *b, int *out_unlinked);
* `link` != 0 links, 0 unlinks).
*/
int oaknode_node_link_undoable(OakNodeNode *a, OakNodeNode *b, int link,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief 1 if the two nodes are linked (Node::are_linked()).
@@ -477,7 +477,7 @@ int oaknode_node_set_context_position(OakNodeNode *node, OakNodeNode *context,
int oaknode_node_set_context_position_undoable(OakNodeNode *node,
OakNodeNode *context, double x,
double y, int expanded,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Remove the node from `context` directly (live).
@@ -504,7 +504,7 @@ OakNodeNode *oaknode_node_create_copy(const OakNodeNode *node);
* until then. Returns NULL on failure.
*/
OakNodeNode *oaknode_node_copy_in_graph(OakNodeNode *node,
OakUndoCommand **out_command);
OakUndoCommand *out_command);
/**
* @brief Get the project this node belongs to (borrowed). *out may be
@@ -537,7 +537,7 @@ int oaknode_node_disconnect_element(OakNodeNode *input_node,
* @brief Create a command that adds a node to a project's graph
* (olive::NodeAddCommand). Owned; free with oakundo_command_free().
*/
OakUndoCommand *oaknode_command_create_add_node(OakNodeProject *graph,
OakUndoCommand oaknode_command_create_add_node(OakNodeProject *graph,
OakNodeNode *node);
/**
@@ -545,7 +545,7 @@ OakUndoCommand *oaknode_command_create_add_node(OakNodeProject *graph,
* repositions its dependencies recursively
* (olive::NodeSetPositionAndDependenciesRecursivelyCommand). Owned.
*/
OakUndoCommand *oaknode_command_create_set_position_recursive(
OakUndoCommand oaknode_command_create_set_position_recursive(
OakNodeNode *node, OakNodeNode *context, double x, double y);
/**
@@ -607,7 +607,7 @@ int oaknode_node_find_input_footage(const OakNodeNode *node,
* Owned command handle; free with oakundo_command_free(). Returns NULL
* on failure.
*/
OakUndoCommand *oaknode_command_create_remove_node(OakNodeNode *node);
OakUndoCommand oaknode_command_create_remove_node(OakNodeNode *node);
/**
* @brief Destroy an OWNED node immediately (C++ delete). NULL is a no-op.
+1 -1
View File
@@ -57,7 +57,7 @@ OakTaskTask *oaktask_create_project_import(OakNodeFolder *folder,
int url_count);
/** @brief Take the import's undo command (ownership transfer). */
OakUndoCommand *oaktask_import_take_command(OakTaskTask *t);
OakUndoCommand oaktask_import_take_command(OakTaskTask *t);
int oaktask_import_footage_count(OakTaskTask *t);
+11 -11
View File
@@ -41,60 +41,60 @@ extern "C" {
*/
/** @brief olive::TimelineAddTrackCommand. */
OakUndoCommand *oaktimeline_add_track_command(OakNodeTrackList *list);
OakUndoCommand oaktimeline_add_track_command(OakNodeTrackList *list);
/** @brief olive::TimelineRemoveTrackCommand. */
OakUndoCommand *oaktimeline_remove_track_command(OakNodeTrack *track);
OakUndoCommand oaktimeline_remove_track_command(OakNodeTrack *track);
/** @brief olive::TrackPlaceBlockCommand. */
OakUndoCommand *oaktimeline_place_block_command(OakNodeTrackList *list,
OakUndoCommand oaktimeline_place_block_command(OakNodeTrackList *list,
int track_index,
OakNodeBlock *block,
int64_t in_num,
int64_t in_den);
/** @brief olive::TrackReplaceBlockWithGapCommand. */
OakUndoCommand *oaktimeline_replace_block_with_gap_command(
OakUndoCommand oaktimeline_replace_block_with_gap_command(
OakNodeTrack *track, OakNodeBlock *block);
/**
* @brief olive::BlockTrimCommand. `mode` is an OakTimelineMovementMode
* value (k_trim_in / k_trim_out).
*/
OakUndoCommand *oaktimeline_trim_command(OakNodeTrack *track,
OakUndoCommand oaktimeline_trim_command(OakNodeTrack *track,
OakNodeBlock *block,
int64_t new_length_num,
int64_t new_length_den, int mode);
/** @brief olive::BlockSplitCommand on a set of blocks at one point. */
OakUndoCommand *oaktimeline_split_command(OakNodeBlock *const *blocks,
OakUndoCommand oaktimeline_split_command(OakNodeBlock *const *blocks,
int count, int64_t point_num,
int64_t point_den);
/** @brief olive::BlockSplitPreservingLinksCommand. */
OakUndoCommand *oaktimeline_split_preserving_links_command(
OakUndoCommand oaktimeline_split_preserving_links_command(
OakNodeBlock *const *blocks, int count, const int64_t *point_nums,
const int64_t *point_dens, int time_count);
/** @brief olive::TimelineRippleDeleteGapsAtRegionsCommand. */
OakUndoCommand *oaktimeline_ripple_delete_gaps_command(
OakUndoCommand oaktimeline_ripple_delete_gaps_command(
OakNodeSequence *sequence, const int64_t *in_nums,
const int64_t *in_dens, const int64_t *out_nums,
const int64_t *out_dens, OakNodeTrack *const *tracks, int range_count);
/** @brief olive::TrackSlideCommand. */
OakUndoCommand *oaktimeline_slide_command(
OakUndoCommand oaktimeline_slide_command(
OakNodeTrack *track, OakNodeBlock *const *blocks, int block_count,
OakNodeBlock *in_adjacent, OakNodeBlock *out_adjacent,
int64_t movement_num, int64_t movement_den);
/** @brief olive::TrackRippleRemoveAreaCommand. */
OakUndoCommand *oaktimeline_ripple_remove_area_command(
OakUndoCommand oaktimeline_ripple_remove_area_command(
OakNodeTrack *track, int64_t in_num, int64_t in_den, int64_t out_num,
int64_t out_den);
/** @brief olive::TrackListInsertGaps. */
OakUndoCommand *oaktimeline_insert_gaps_command(OakNodeTrackList *list,
OakUndoCommand oaktimeline_insert_gaps_command(OakNodeTrackList *list,
int64_t point_num,
int64_t point_den,
int64_t length_num,
+4 -4
View File
@@ -65,7 +65,7 @@ int oaktimeline_marker_at(const OakTimelineMarkerList *list, int index,
* Owned command; free with oakundo_command_free(). Redo it directly or
* push it on an undo stack. Returns NULL on failure.
*/
OakUndoCommand *oaktimeline_marker_add_command(
OakUndoCommand oaktimeline_marker_add_command(
OakTimelineMarkerList *list, int in_num, int in_den, int out_num,
int out_den, const char *name, int color);
@@ -74,13 +74,13 @@ OakUndoCommand *oaktimeline_marker_add_command(
* OAKTIMELINE_E_NOT_FOUND (as NULL result documented by error) is
* reported by returning NULL.
*/
OakUndoCommand *oaktimeline_marker_remove_at_command(
OakUndoCommand oaktimeline_marker_remove_at_command(
OakTimelineMarkerList *list, int index);
/**
* @brief Create a command that sets a marker's time range.
*/
OakUndoCommand *oaktimeline_marker_set_time_command(
OakUndoCommand oaktimeline_marker_set_time_command(
OakTimelineMarkerList *list, int index, int in_num, int in_den,
int out_num, int out_den);
@@ -89,7 +89,7 @@ OakUndoCommand *oaktimeline_marker_set_time_command(
* `name` may be NULL to leave the name unchanged (color still applies
* when >= 0; both NULL-name and color < 0 is a no-op error).
*/
OakUndoCommand *oaktimeline_marker_set_props_command(
OakUndoCommand oaktimeline_marker_set_props_command(
OakTimelineMarkerList *list, int index, int color, const char *name);
/**
+2 -2
View File
@@ -60,7 +60,7 @@ int oaktimeline_workarea_set_range(OakTimelineWorkArea *w, int in_num,
* The old range must be supplied by the caller (facade knows what it
* changed from). Owned; free with oakundo_command_free().
*/
OakUndoCommand *oaktimeline_workarea_set_range_command(
OakUndoCommand oaktimeline_workarea_set_range_command(
OakTimelineWorkArea *w, int in_num, int in_den, int out_num,
int out_den, int old_in_num, int old_in_den, int old_out_num,
int old_out_den);
@@ -68,7 +68,7 @@ OakUndoCommand *oaktimeline_workarea_set_range_command(
/**
* @brief Create a set-enabled command (olive::WorkareaSetEnabledCommand).
*/
OakUndoCommand *oaktimeline_workarea_set_enabled_command(
OakUndoCommand oaktimeline_workarea_set_enabled_command(
OakTimelineWorkArea *w, int enabled);
/**
+47 -35
View File
@@ -21,31 +21,43 @@
#ifndef OAK_EDITOR_UNDO_UNDOCOMMAND_H
#define OAK_EDITOR_UNDO_UNDOCOMMAND_H
#include <stdint.h>
#include "undo/error.h"
#ifdef __cplusplus
extern "C" {
#endif
#define OAKUNDO_ABI_VERSION 1
/**
* @brief Opaque handle to an undo command (olive::UndoCommand).
* @brief Reference-counted handle to an undo command
* (olive::UndoCommand).
*
* Handles created by oakundo_command_init() /
* oakundo_command_init_multi() own the underlying command and must be
* released with oakundo_command_free() UNLESS they are pushed onto an
* OakUndoStack, which takes ownership. Handles returned by
* oakundo_command_multi_child() are borrowed wrappers: free the wrapper
* with oakundo_command_free(), the underlying command stays owned by the
* multi command.
* The object never leaves the library that created it; every external
* reference is one of these handles. Semantics are shared_ptr-like:
* init/factory functions return a handle with count 1, addref(ctx)
* takes another reference, release(ctx) drops one and the library
* destroys the object when the count reaches zero.
*
* Pushing a command onto an OakUndoStack transfers one reference to the
* stack (the stack releases it when the command is discarded); callers
* may keep their own reference or release it right after the push.
*/
typedef struct OakUndoCommand OakUndoCommand;
typedef struct OakUndoCommand {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKUNDO_ABI_VERSION. */
} OakUndoCommand;
/**
* @brief Callback table backing a caller-defined undo command.
*
* Any callback may be NULL; a NULL redo/undo makes that direction a
* no-op. free_fn is invoked when the command is destroyed (whether pushed
* onto a stack or freed directly) and releases userdata.
* no-op. free_fn is invoked when the command is destroyed (whether held
* by a stack or released directly) and releases userdata.
*/
typedef struct OakUndoCommandVtable {
void (*redo)(void *userdata);
@@ -58,30 +70,30 @@ typedef struct OakUndoCommandVtable {
*
* The command takes ownership of `userdata`; `vtable` is copied.
*
* @return Command handle, or NULL on invalid argument or allocation
* failure.
* @return Command handle with count 1; ctx is NULL on invalid argument
* or allocation failure.
*/
OakUndoCommand *oakundo_command_init(const OakUndoCommandVtable *vtable,
void *userdata);
OakUndoCommand oakundo_command_init(const OakUndoCommandVtable *vtable,
void *userdata);
/**
* @brief Create an empty multi command (olive::MultiUndoCommand).
*
* @return Command handle, or NULL on allocation failure.
* @return Command handle with count 1; ctx is NULL on allocation
* failure.
*/
OakUndoCommand *oakundo_command_init_multi(void);
OakUndoCommand oakundo_command_init_multi(void);
/**
* @brief Add `child` to the multi command `multi`.
*
* On success the multi command takes ownership of the underlying child
* command; the child handle wrapper is consumed and must not be used or
* freed afterwards.
* The multi command takes one reference to the child; the caller keeps
* its own reference and may release it after the call.
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_command_multi_add_child(OakUndoCommand *multi,
OakUndoCommand *child);
int oakundo_command_multi_add_child(OakUndoCommand multi,
OakUndoCommand child);
/**
* @brief Query the number of children in a multi command.
@@ -90,19 +102,20 @@ int oakundo_command_multi_add_child(OakUndoCommand *multi,
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_command_multi_child_count(OakUndoCommand *multi, int *out_count);
int oakundo_command_multi_child_count(OakUndoCommand multi,
int *out_count);
/**
* @brief Borrow a handle to the child at `index` of a multi command.
* @brief Reference to the child at `index` of a multi command.
*
* The returned handle is a wrapper owned by the caller (free with
* oakundo_command_free()); the underlying command is owned by `multi`.
* The returned handle carries its own reference; release it with
* oakundo_command_free().
*
* @return OAKUNDO_OK, OAKUNDO_E_NOT_FOUND for an out-of-range index, or
* another negative OAKUNDO_E_* error code.
*/
int oakundo_command_multi_child(OakUndoCommand *multi, int index,
OakUndoCommand **out_child);
int oakundo_command_multi_child(OakUndoCommand multi, int index,
OakUndoCommand *out_child);
/**
* @brief Execute the command's redo without a stack
@@ -110,7 +123,7 @@ int oakundo_command_multi_child(OakUndoCommand *multi, int index,
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_command_redo_now(OakUndoCommand *command);
int oakundo_command_redo_now(OakUndoCommand command);
/**
* @brief Execute the command's undo without a stack
@@ -118,15 +131,14 @@ int oakundo_command_redo_now(OakUndoCommand *command);
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_command_undo_now(OakUndoCommand *command);
int oakundo_command_undo_now(OakUndoCommand command);
/**
* @brief Destroy a command handle.
* @brief Release one reference to a command handle.
*
* Owned handles destroy the underlying command; borrowed handles (from
* oakundo_command_multi_child()) only destroy the wrapper. Commands
* pushed onto an OakUndoStack are owned by the stack and must not be
* freed by the caller. NULL is a no-op.
* Convenience wrapper around handle.release(handle.ctx): destroys the
* command when the count reaches zero. NULL handle or NULL ctx is a
* no-op; clears `command->ctx` after releasing.
*/
void oakundo_command_free(OakUndoCommand *command);
+35 -26
View File
@@ -31,50 +31,59 @@ extern "C" {
#endif
/**
* @brief Opaque handle to an undo stack (olive::UndoStack).
* @brief Reference-counted handle to an undo stack (olive::UndoStack).
*
* Same ownership/count semantics as OakUndoCommand (see
* undo/undocommand.h).
*/
typedef struct OakUndoStack OakUndoStack;
typedef struct OakUndoStack {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKUNDO_ABI_VERSION. */
} OakUndoStack;
/**
* @brief Create an undo stack.
* @brief Create an undo stack (count 1).
*
* A fresh stack contains a single "New/Open Project" empty command,
* matching olive::UndoStack::clear().
*
* @return Stack handle, or NULL on allocation failure.
* @return Stack handle; ctx is NULL on allocation failure.
*/
OakUndoStack *oakundo_undostack_init(void);
OakUndoStack oakundo_undostack_init(void);
/**
* @brief Destroy an undo stack and all commands it owns.
* @brief Release one reference to an undo stack.
*
* NULL is a no-op.
* NULL handle or NULL ctx is a no-op; clears `stack->ctx` after
* releasing.
*/
void oakundo_undostack_free(OakUndoStack *stack);
/**
* @brief Push `command` onto the stack and execute its redo.
*
* On success the stack takes ownership of the underlying command; the
* handle wrapper is consumed and must not be used or freed afterwards.
* An empty multi command is deleted immediately (not pushed), matching
* olive::UndoStack::push. `name` is the user-visible label (NULL behaves
* like an empty label).
* The stack takes one reference to the command; the caller keeps its
* own reference and may release it after the call. An empty multi
* command is deleted immediately (not pushed), matching
* olive::UndoStack::push. `name` is the user-visible label (NULL
* behaves like an empty label).
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_push(OakUndoStack *stack, OakUndoCommand *command,
int oakundo_undostack_push(OakUndoStack stack, OakUndoCommand command,
const char *name);
/**
* @brief Push a command that has already been executed (redo skipped).
*
* Ownership rules match oakundo_undostack_push().
* Reference rules match oakundo_undostack_push().
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_push_pre_executed(OakUndoStack *stack,
OakUndoCommand *command,
int oakundo_undostack_push_pre_executed(OakUndoStack stack,
OakUndoCommand command,
const char *name);
/**
@@ -82,14 +91,14 @@ int oakundo_undostack_push_pre_executed(OakUndoStack *stack,
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_undo(OakUndoStack *stack);
int oakundo_undostack_undo(OakUndoStack stack);
/**
* @brief Redo the most recently undone command, if any.
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_redo(OakUndoStack *stack);
int oakundo_undostack_redo(OakUndoStack stack);
/**
* @brief Undo/redo until the done-command count equals `index`
@@ -97,7 +106,7 @@ int oakundo_undostack_redo(OakUndoStack *stack);
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_jump(OakUndoStack *stack, int64_t index);
int oakundo_undostack_jump(OakUndoStack stack, int64_t index);
/**
* @brief Delete all commands and push the fresh "New/Open Project" empty
@@ -105,7 +114,7 @@ int oakundo_undostack_jump(OakUndoStack *stack, int64_t index);
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_clear(OakUndoStack *stack);
int oakundo_undostack_clear(OakUndoStack stack);
/**
* @brief Query whether undo (redo) is currently possible.
@@ -114,8 +123,8 @@ int oakundo_undostack_clear(OakUndoStack *stack);
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_can_undo(OakUndoStack *stack, int *out_value);
int oakundo_undostack_can_redo(OakUndoStack *stack, int *out_value);
int oakundo_undostack_can_undo(OakUndoStack stack, int *out_value);
int oakundo_undostack_can_redo(OakUndoStack stack, int *out_value);
/**
* @brief Total number of history rows (done + undone commands).
@@ -124,7 +133,7 @@ int oakundo_undostack_can_redo(OakUndoStack *stack, int *out_value);
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_count(OakUndoStack *stack, int64_t *out_count);
int oakundo_undostack_count(OakUndoStack stack, int64_t *out_count);
/**
* @brief Current position in the history: the number of done commands
@@ -134,7 +143,7 @@ int oakundo_undostack_count(OakUndoStack *stack, int64_t *out_count);
*
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_index(OakUndoStack *stack, int64_t *out_index);
int oakundo_undostack_index(OakUndoStack stack, int64_t *out_index);
/**
* @brief Label of the history row at `row` (0-based, two-stage getter).
@@ -143,7 +152,7 @@ int oakundo_undostack_index(OakUndoStack *stack, int64_t *out_index);
* (non-negative), OAKUNDO_E_NOT_FOUND for an invalid row, or
* another negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_command_text(OakUndoStack *stack, int64_t row,
int oakundo_undostack_command_text(OakUndoStack stack, int64_t row,
char *buf, int buf_size);
/**
@@ -154,7 +163,7 @@ int oakundo_undostack_command_text(OakUndoStack *stack, int64_t row,
* @return OAKUNDO_OK, OAKUNDO_E_NOT_FOUND for an invalid row, or another
* negative OAKUNDO_E_* error code.
*/
int oakundo_undostack_command_is_done(OakUndoStack *stack, int64_t row,
int oakundo_undostack_command_is_done(OakUndoStack stack, int64_t row,
int *out_value);
#ifdef __cplusplus
+8 -12
View File
@@ -238,24 +238,20 @@ OakNodeNode *oaknode_folder_as_node(OakNodeFolder *folder)
return reinterpret_cast<OakNodeNode *>(folder);
}
OakUndoCommand *oaknode_command_create_folder_add_child(
OakUndoCommand oaknode_command_create_folder_add_child(
OakNodeFolder *folder, OakNodeNode *child)
{
if (!folder || !child) {
return NULL;
return OakUndoCommand{};
}
try {
OakUndoCommand *handle =
new (std::nothrow) OakUndoCommand{ nullptr, true };
if (!handle) {
return NULL;
}
handle->command = new olive::FolderAddChild(
reinterpret_cast<olive::Folder *>(folder),
reinterpret_cast<olive::Node *>(child));
return handle;
return oakundo_capi::make_command_handle(
new olive::FolderAddChild(
reinterpret_cast<olive::Folder *>(folder),
reinterpret_cast<olive::Node *>(child)),
true);
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
+6 -6
View File
@@ -111,18 +111,18 @@ int oaknode_group_add_input_passthrough_undoable(OakNodeGroup *group,
OakNodeNode *node,
const char *input_id,
int element,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!group || !node || !input_id || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeGroupAddInputPassthrough(
to_group(group),
olive::NodeInput(to_node(node), input_id, element)));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -246,17 +246,17 @@ int oaknode_group_set_output_passthrough(OakNodeGroup *group,
}
int oaknode_group_set_output_passthrough_undoable(
OakNodeGroup *group, OakNodeNode *node, OakUndoCommand **out_command)
OakNodeGroup *group, OakNodeNode *node, OakUndoCommand *out_command)
{
if (!group || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeGroupSetOutputPassthrough(to_group(group),
to_node(node)));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
+15 -15
View File
@@ -213,19 +213,19 @@ int oaknode_keyframe_set_time(OakNodeKeyframe *keyframe, int64_t time_num,
int oaknode_keyframe_set_time_undoable(OakNodeKeyframe *keyframe,
int64_t time_num, int64_t time_den,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!keyframe || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeParamSetKeyframeTimeCommand(
to_key(keyframe),
olive::core::Rational(static_cast<int>(time_num),
static_cast<int>(time_den))));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -316,7 +316,7 @@ int oaknode_keyframe_set_value(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_value_undoable(OakNodeKeyframe *keyframe,
const oaknode_value *v,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!keyframe || !v || !out_command) {
return OAKNODE_E_INVALID;
@@ -328,10 +328,10 @@ int oaknode_keyframe_set_value_undoable(OakNodeKeyframe *keyframe,
return OAKNODE_E_INVALID;
}
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeParamSetKeyframeValueCommand(to_key(keyframe),
variant));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -373,17 +373,17 @@ int oaknode_keyframe_set_value_string(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_value_string_undoable(OakNodeKeyframe *keyframe,
const char *value,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!keyframe || !value || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeParamSetKeyframeValueCommand(
to_key(keyframe), olive::Variant(value)));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -426,7 +426,7 @@ int oaknode_keyframe_set_type(OakNodeKeyframe *keyframe, int type)
}
int oaknode_keyframe_set_type_undoable(OakNodeKeyframe *keyframe, int type,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!keyframe || !out_command) {
return OAKNODE_E_INVALID;
@@ -438,9 +438,9 @@ int oaknode_keyframe_set_type_undoable(OakNodeKeyframe *keyframe, int type,
return OAKNODE_E_INVALID;
}
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new KeyframeSetTypeCommand(to_key(keyframe), keyframe_type));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -498,7 +498,7 @@ int oaknode_keyframe_set_bezier_control(OakNodeKeyframe *keyframe, int handle,
int oaknode_keyframe_set_bezier_control_undoable(OakNodeKeyframe *keyframe,
int handle, double x, double y,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!keyframe || !out_command) {
return OAKNODE_E_INVALID;
@@ -514,10 +514,10 @@ int oaknode_keyframe_set_bezier_control_undoable(OakNodeKeyframe *keyframe,
return OAKNODE_E_INVALID;
}
OakUndoCommand *handle_ptr = oaknode_c_api::wrap_command(
OakUndoCommand handle_ptr = oaknode_c_api::wrap_command(
new KeyframeSetBezierControlCommand(to_key(keyframe), bezier_handle,
olive::PointF(x, y)));
if (!handle_ptr) {
if (!handle_ptr.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle_ptr;
+38 -38
View File
@@ -167,16 +167,16 @@ int oaknode_node_set_label(OakNodeNode *node, const char *label)
}
int oaknode_node_set_label_undoable(OakNodeNode *node, const char *label,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !label || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeRenameCommand(to_node(node), label));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -215,16 +215,16 @@ int oaknode_node_set_override_color(OakNodeNode *node, int index)
}
int oaknode_node_set_override_color_undoable(OakNodeNode *node, int index,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeOverrideColorCommand(to_node(node), index));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -268,7 +268,7 @@ int oaknode_node_set_enabled(OakNodeNode *node, int enabled)
}
int oaknode_node_set_enabled_undoable(OakNodeNode *node, int enabled,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !out_command) {
return OAKNODE_E_INVALID;
@@ -279,9 +279,9 @@ int oaknode_node_set_enabled_undoable(OakNodeNode *node, int enabled,
olive::SplitValue split =
olive::NodeValue::split_normal_value_into_track_values(
olive::NodeValue::k_boolean, olive::Variant(enabled != 0));
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeParamSetSplitStandardValueCommand(ref, split));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -464,7 +464,7 @@ int oaknode_node_set_input(OakNodeNode *node, const char *input_id,
int oaknode_node_set_input_undoable(OakNodeNode *node, const char *input_id,
const oaknode_value *v,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !out_command) {
return OAKNODE_E_INVALID;
@@ -485,9 +485,9 @@ int oaknode_node_set_input_undoable(OakNodeNode *node, const char *input_id,
olive::SplitValue split =
olive::NodeValue::split_normal_value_into_track_values(type, variant);
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeParamSetSplitStandardValueCommand(ref, split));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -545,7 +545,7 @@ int oaknode_node_set_input_string(OakNodeNode *node, const char *input_id,
int oaknode_node_set_input_string_undoable(OakNodeNode *node,
const char *input_id,
const char *value,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !value || !out_command) {
return OAKNODE_E_INVALID;
@@ -566,9 +566,9 @@ int oaknode_node_set_input_string_undoable(OakNodeNode *node,
to_node(node)->get_input_data_type(input_id),
olive::Variant(value));
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeParamSetSplitStandardValueCommand(ref, split));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -610,7 +610,7 @@ int oaknode_node_connect(OakNodeNode *output_node, OakNodeNode *input_node,
int oaknode_node_connect_undoable(OakNodeNode *output_node,
OakNodeNode *input_node,
const char *input_id,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!output_node || !input_node || !out_command) {
return OAKNODE_E_INVALID;
@@ -624,11 +624,11 @@ int oaknode_node_connect_undoable(OakNodeNode *output_node,
return OAKNODE_E_INVALID;
}
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeEdgeAddCommand(
to_node(output_node),
olive::NodeInput(to_node(input_node), input_id)));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -663,7 +663,7 @@ int oaknode_node_disconnect(OakNodeNode *input_node, const char *input_id)
int oaknode_node_disconnect_undoable(OakNodeNode *input_node,
const char *input_id,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!input_node || !out_command) {
return OAKNODE_E_INVALID;
@@ -678,10 +678,10 @@ int oaknode_node_disconnect_undoable(OakNodeNode *input_node,
return OAKNODE_E_NOT_FOUND;
}
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeEdgeRemoveCommand(
output, olive::NodeInput(to_node(input_node), input_id)));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -804,16 +804,16 @@ int oaknode_node_unlink(OakNodeNode *a, OakNodeNode *b, int *out_unlinked)
}
int oaknode_node_link_undoable(OakNodeNode *a, OakNodeNode *b, int link,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!a || !b || !out_command) {
return OAKNODE_E_INVALID;
}
try {
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeLinkCommand(to_node(a), to_node(b), link != 0));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -964,7 +964,7 @@ int oaknode_node_set_context_position(OakNodeNode *node, OakNodeNode *context,
int oaknode_node_set_context_position_undoable(OakNodeNode *node,
OakNodeNode *context, double x,
double y, int expanded,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !context || !out_command) {
return OAKNODE_E_INVALID;
@@ -977,10 +977,10 @@ int oaknode_node_set_context_position_undoable(OakNodeNode *node,
// position map lives on the positioned node keyed by the context,
// so the command's (node, context) arguments are swapped relative
// to this function's signature.
OakUndoCommand *handle = oaknode_c_api::wrap_command(
OakUndoCommand handle = oaknode_c_api::wrap_command(
new olive::NodeSetPositionCommand(to_node(context), to_node(node),
position));
if (!handle) {
if (!handle.ctx) {
return OAKNODE_E_NOMEM;
}
*out_command = handle;
@@ -1039,7 +1039,7 @@ void oaknode_node_free(OakNodeNode *node)
}
OakNodeNode *oaknode_node_copy_in_graph(OakNodeNode *node,
OakUndoCommand **out_command)
OakUndoCommand *out_command)
{
if (!node || !out_command) {
return NULL;
@@ -1054,7 +1054,7 @@ OakNodeNode *oaknode_node_copy_in_graph(OakNodeNode *node,
return NULL;
}
*out_command = oaknode_c_api::wrap_command(command);
if (!*out_command) {
if (!out_command->ctx) {
delete command;
return NULL;
}
@@ -1065,10 +1065,10 @@ OakNodeNode *oaknode_node_copy_in_graph(OakNodeNode *node,
}
}
OakUndoCommand *oaknode_command_create_remove_node(OakNodeNode *node)
OakUndoCommand oaknode_command_create_remove_node(OakNodeNode *node)
{
if (!node) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -1076,7 +1076,7 @@ OakUndoCommand *oaknode_command_create_remove_node(OakNodeNode *node)
new olive::NodeRemoveWithExclusiveDependenciesAndDisconnect(
to_node(node)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
@@ -1171,11 +1171,11 @@ int oaknode_node_disconnect_element(OakNodeNode *input_node,
}
}
OakUndoCommand *oaknode_command_create_add_node(OakNodeProject *graph,
OakUndoCommand oaknode_command_create_add_node(OakNodeProject *graph,
OakNodeNode *node)
{
if (!graph || !node) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -1183,15 +1183,15 @@ OakUndoCommand *oaknode_command_create_add_node(OakNodeProject *graph,
new olive::NodeAddCommand(
reinterpret_cast<olive::Project *>(graph), to_node(node)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaknode_command_create_set_position_recursive(
OakUndoCommand oaknode_command_create_set_position_recursive(
OakNodeNode *node, OakNodeNode *context, double x, double y)
{
if (!node || !context) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -1200,7 +1200,7 @@ OakUndoCommand *oaknode_command_create_set_position_recursive(
to_node(node), to_node(context),
olive::Node::Position(olive::PointF(x, y))));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
+5 -12
View File
@@ -250,22 +250,15 @@ inline int value_from_variant(olive::NodeValue::Type type, const olive::Variant
/**
* @brief Wrap a freshly created olive::UndoCommand in an owned
* OakUndoCommand handle. Returns NULL on allocation failure.
* OakUndoCommand handle (reference count 1). Returns an empty handle
* (ctx == NULL) on allocation failure.
*/
inline OakUndoCommand *wrap_command(olive::UndoCommand *command)
inline OakUndoCommand wrap_command(olive::UndoCommand *command)
{
if (!command) {
return NULL;
return OakUndoCommand{};
}
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand();
if (!handle) {
delete command;
return NULL;
}
handle->command = command;
handle->owned = true;
return handle;
return oakundo_capi::make_command_handle(command, true);
}
}
+6 -6
View File
@@ -136,11 +136,11 @@ TEST(NodeGroupTest, PassthroughAddUndoable)
OakNodeGroup *group = make_group_with_inner(as_handle(&inner));
ASSERT_NE(group, nullptr);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_group_add_input_passthrough_undoable(
group, as_handle(&inner), "float_in", -1, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
int count = 0;
EXPECT_EQ(oaknode_group_passthrough_count(group, &count), OAKNODE_OK);
@@ -154,7 +154,7 @@ TEST(NodeGroupTest, PassthroughAddUndoable)
EXPECT_EQ(oaknode_group_passthrough_count(group, &count), OAKNODE_OK);
EXPECT_EQ(count, 0);
oakundo_command_free(command);
oakundo_command_free(&command);
oaknode_group_free(group);
}
@@ -174,18 +174,18 @@ TEST(NodeGroupTest, OutputPassthroughLiveAndUndoable)
EXPECT_EQ(oaknode_group_get_output_passthrough(group, &out), OAKNODE_OK);
EXPECT_EQ(out, inner_handle);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_group_set_output_passthrough_undoable(group, nullptr,
&command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_group_get_output_passthrough(group, &out), OAKNODE_OK);
EXPECT_EQ(out, nullptr);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_group_get_output_passthrough(group, &out), OAKNODE_OK);
EXPECT_EQ(out, inner_handle);
oakundo_command_free(command);
oakundo_command_free(&command);
EXPECT_EQ(oaknode_group_set_output_passthrough(nullptr, inner_handle),
OAKNODE_E_INVALID);
+15 -15
View File
@@ -124,10 +124,10 @@ TEST(NodeKeyframeTest, TimeLiveAndUndoable)
EXPECT_EQ(num, 1);
EXPECT_EQ(den, 2);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_keyframe_set_time_undoable(key, 5, 1, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oaknode_keyframe_get_time(key, &num, &den), OAKNODE_OK);
EXPECT_EQ(num, 1); // not yet executed
@@ -138,7 +138,7 @@ TEST(NodeKeyframeTest, TimeLiveAndUndoable)
EXPECT_EQ(oaknode_keyframe_get_time(key, &num, &den), OAKNODE_OK);
EXPECT_EQ(num, 1);
oakundo_command_free(command);
oakundo_command_free(&command);
oaknode_keyframe_free(key);
EXPECT_EQ(oaknode_keyframe_set_time(nullptr, 0, 1), OAKNODE_E_INVALID);
@@ -163,17 +163,17 @@ TEST(NodeKeyframeTest, ValueLiveAndUndoable)
EXPECT_DOUBLE_EQ(out.f[0], 3.25);
in = make_float(7.0);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_keyframe_set_value_undoable(key, &in, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_value(key, &out), OAKNODE_OK);
EXPECT_DOUBLE_EQ(out.f[0], 7.0);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_value(key, &out), OAKNODE_OK);
EXPECT_DOUBLE_EQ(out.f[0], 3.25);
oakundo_command_free(command);
oakundo_command_free(&command);
// STRING rejected by the POD setter.
in.type = OAKNODE_VALUE_STRING;
@@ -195,18 +195,18 @@ TEST(NodeKeyframeTest, StringValueLiveAndUndoable)
EXPECT_EQ(oaknode_keyframe_get_value_string(key, buf, sizeof(buf)), 6);
EXPECT_STREQ(buf, "hello");
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_keyframe_set_value_string_undoable(key, "world",
&command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_value_string(key, buf, sizeof(buf)), 6);
EXPECT_STREQ(buf, "world");
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_value_string(key, buf, sizeof(buf)), 6);
EXPECT_STREQ(buf, "hello");
oakundo_command_free(command);
oakundo_command_free(&command);
EXPECT_EQ(oaknode_keyframe_set_value_string(key, nullptr),
OAKNODE_E_INVALID);
@@ -229,18 +229,18 @@ TEST(NodeKeyframeTest, TypeLiveAndUndoable)
EXPECT_EQ(oaknode_keyframe_get_type(key, &type), OAKNODE_OK);
EXPECT_EQ(type, OAKNODE_KEYFRAME_HOLD);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_keyframe_set_type_undoable(key, OAKNODE_KEYFRAME_BEZIER,
&command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_type(key, &type), OAKNODE_OK);
EXPECT_EQ(type, OAKNODE_KEYFRAME_BEZIER);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_type(key, &type), OAKNODE_OK);
EXPECT_EQ(type, OAKNODE_KEYFRAME_HOLD);
oakundo_command_free(command);
oakundo_command_free(&command);
EXPECT_EQ(oaknode_keyframe_set_type(key, 99), OAKNODE_E_INVALID);
EXPECT_EQ(oaknode_keyframe_set_type(nullptr, OAKNODE_KEYFRAME_HOLD),
@@ -266,11 +266,11 @@ TEST(NodeKeyframeTest, BezierControlLiveAndUndoable)
EXPECT_DOUBLE_EQ(x, -1.0);
EXPECT_DOUBLE_EQ(y, 0.5);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_keyframe_set_bezier_control_undoable(
key, OAKNODE_KEYFRAME_OUT_HANDLE, 2.0, -0.5, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_keyframe_get_bezier_control(
key, OAKNODE_KEYFRAME_OUT_HANDLE, &x, &y),
@@ -283,7 +283,7 @@ TEST(NodeKeyframeTest, BezierControlLiveAndUndoable)
OAKNODE_OK);
EXPECT_DOUBLE_EQ(x, 0.0);
EXPECT_DOUBLE_EQ(y, 0.0);
oakundo_command_free(command);
oakundo_command_free(&command);
EXPECT_EQ(oaknode_keyframe_set_bezier_control(key, 99, 0.0, 0.0),
OAKNODE_E_INVALID);
+27 -27
View File
@@ -117,10 +117,10 @@ TEST(NodeMetadataTest, LabelUndoableSymmetry)
EXPECT_EQ(oaknode_node_set_label(handle, "before"), OAKNODE_OK);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_set_label_undoable(handle, "after", &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(get_string(oaknode_node_get_label, handle), "before");
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
@@ -128,7 +128,7 @@ TEST(NodeMetadataTest, LabelUndoableSymmetry)
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(get_string(oaknode_node_get_label, handle), "before");
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(NodeMetadataTest, OverrideColorLiveAndUndoable)
@@ -144,17 +144,17 @@ TEST(NodeMetadataTest, OverrideColorLiveAndUndoable)
EXPECT_EQ(oaknode_node_get_override_color(handle, &color), OAKNODE_OK);
EXPECT_EQ(color, 3);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_set_override_color_undoable(handle, 7, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_get_override_color(handle, &color), OAKNODE_OK);
EXPECT_EQ(color, 7);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_get_override_color(handle, &color), OAKNODE_OK);
EXPECT_EQ(color, 3);
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(NodeMetadataTest, EnabledLiveAndUndoable)
@@ -170,17 +170,17 @@ TEST(NodeMetadataTest, EnabledLiveAndUndoable)
EXPECT_EQ(oaknode_node_is_enabled(handle, &enabled), OAKNODE_OK);
EXPECT_EQ(enabled, 0);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_set_enabled_undoable(handle, 1, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_is_enabled(handle, &enabled), OAKNODE_OK);
EXPECT_EQ(enabled, 1);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_is_enabled(handle, &enabled), OAKNODE_OK);
EXPECT_EQ(enabled, 0);
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(NodeInputTest, EnumerateInputs)
@@ -302,10 +302,10 @@ TEST(NodeInputTest, ValueUndoableSymmetry)
OakNodeNode *handle = as_handle(&node);
oaknode_value in = make_float(9.0);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_set_input_undoable(handle, "float_in", &in, &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
oaknode_value out;
EXPECT_EQ(oaknode_node_get_input(handle, "float_in", &out), OAKNODE_OK);
@@ -317,7 +317,7 @@ TEST(NodeInputTest, ValueUndoableSymmetry)
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_get_input(handle, "float_in", &out), OAKNODE_OK);
EXPECT_DOUBLE_EQ(out.f[0], 0.0);
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(NodeInputTest, StringValueLiveAndUndoable)
@@ -343,11 +343,11 @@ TEST(NodeInputTest, StringValueLiveAndUndoable)
EXPECT_EQ(oaknode_node_set_input_string(handle, "unknown_in", "x"),
OAKNODE_E_NOT_FOUND);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_set_input_string_undoable(handle, "text_in",
"world", &command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_get_input_string(handle, "text_in", buf,
sizeof(buf)),
@@ -358,7 +358,7 @@ TEST(NodeInputTest, StringValueLiveAndUndoable)
sizeof(buf)),
6);
EXPECT_STREQ(buf, "hello");
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(NodeGraphTest, ConnectDisconnectLive)
@@ -424,10 +424,10 @@ TEST(NodeGraphTest, ConnectDisconnectUndoable)
OakNodeNode *src = as_handle(&source);
OakNodeNode *dst = as_handle(&dest);
OakUndoCommand *add = nullptr;
OakUndoCommand add = {};
EXPECT_EQ(oaknode_node_connect_undoable(src, dst, "float_in", &add),
OAKNODE_OK);
ASSERT_NE(add, nullptr);
ASSERT_NE(add.ctx, nullptr);
int connected = 0;
EXPECT_EQ(oakundo_command_redo_now(add), OAKUNDO_OK);
@@ -442,10 +442,10 @@ TEST(NodeGraphTest, ConnectDisconnectUndoable)
// Redo again so the remove command has an edge to work on.
EXPECT_EQ(oakundo_command_redo_now(add), OAKUNDO_OK);
OakUndoCommand *remove = nullptr;
OakUndoCommand remove = {};
EXPECT_EQ(oaknode_node_disconnect_undoable(dst, "float_in", &remove),
OAKNODE_OK);
ASSERT_NE(remove, nullptr);
ASSERT_NE(remove.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(remove), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_input_is_connected(dst, "float_in", &connected),
OAKNODE_OK);
@@ -458,8 +458,8 @@ TEST(NodeGraphTest, ConnectDisconnectUndoable)
EXPECT_EQ(oaknode_node_disconnect_undoable(dst, "int_in", &remove),
OAKNODE_E_NOT_FOUND);
oakundo_command_free(remove);
oakundo_command_free(add);
oakundo_command_free(&remove);
oakundo_command_free(&add);
}
TEST(NodeLinkTest, LinkUnlinkLiveAndUndoable)
@@ -492,16 +492,16 @@ TEST(NodeLinkTest, LinkUnlinkLiveAndUndoable)
EXPECT_EQ(oaknode_node_are_linked(a, b, &linked), OAKNODE_OK);
EXPECT_EQ(linked, 0);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_link_undoable(a, b, 1, &command), OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_are_linked(a, b, &linked), OAKNODE_OK);
EXPECT_EQ(linked, 1);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_are_linked(a, b, &linked), OAKNODE_OK);
EXPECT_EQ(linked, 0);
oakundo_command_free(command);
oakundo_command_free(&command);
EXPECT_EQ(oaknode_node_link(nullptr, b, &done), OAKNODE_E_INVALID);
}
@@ -534,11 +534,11 @@ TEST(NodeContextTest, PositionsLiveAndUndoable)
EXPECT_EQ(entry, ctx);
EXPECT_EQ(oaknode_node_context_node_at(n, 1, &entry), OAKNODE_E_NOT_FOUND);
OakUndoCommand *command = nullptr;
OakUndoCommand command = {};
EXPECT_EQ(oaknode_node_set_context_position_undoable(n, ctx, 1.0, 2.0, 0,
&command),
OAKNODE_OK);
ASSERT_NE(command, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oaknode_node_get_context_position(n, ctx, &x, &y, &expanded),
OAKNODE_OK);
@@ -549,7 +549,7 @@ TEST(NodeContextTest, PositionsLiveAndUndoable)
EXPECT_EQ(oaknode_node_get_context_position(n, ctx, &x, &y, &expanded),
OAKNODE_OK);
EXPECT_DOUBLE_EQ(x, 10.5);
oakundo_command_free(command);
oakundo_command_free(&command);
EXPECT_EQ(oaknode_node_remove_from_context(n, ctx), OAKNODE_OK);
EXPECT_EQ(oaknode_node_remove_from_context(n, ctx), OAKNODE_E_NOT_FOUND);
+2 -2
View File
@@ -118,11 +118,11 @@ OakTaskTask *oaktask_create_project_import(OakNodeFolder *folder,
}
}
OakUndoCommand *oaktask_import_take_command(OakTaskTask *t)
OakUndoCommand oaktask_import_take_command(OakTaskTask *t)
{
olive::ProjectImportTask *task = import_impl(t);
if (!task) {
return NULL;
return OakUndoCommand{};
}
return task->take_command();
}
+10 -10
View File
@@ -65,7 +65,7 @@ ProjectImportTask::ImageSequenceConfirmFn ProjectImportTask::confirm_callback_;
ProjectImportTask::ProjectImportTask(
OakNodeFolder *folder, OakNodeProject *project,
const std::vector<std::string> &filenames)
: command_(nullptr)
: command_({})
, folder_(folder)
, project_(project)
, filenames_(filenames)
@@ -80,8 +80,8 @@ ProjectImportTask::ProjectImportTask(
ProjectImportTask::~ProjectImportTask()
{
if (command_) {
oakundo_command_free(command_);
if (command_.ctx) {
oakundo_command_free(&command_);
}
}
@@ -93,7 +93,7 @@ const int &ProjectImportTask::get_file_count() const
bool ProjectImportTask::run()
{
command_ = oakundo_command_init_multi();
if (!command_) {
if (!command_.ctx) {
set_error("Failed to create import command");
return false;
}
@@ -103,8 +103,8 @@ bool ProjectImportTask::run()
import(folder_, filenames_, imported, command_);
if (is_cancelled()) {
oakundo_command_free(command_);
command_ = nullptr;
oakundo_command_free(&command_);
command_ = OakUndoCommand{};
return false;
}
return true;
@@ -112,7 +112,7 @@ bool ProjectImportTask::run()
void ProjectImportTask::import(OakNodeFolder *folder,
const std::vector<std::string> &entries,
int &counter, OakUndoCommand *parent_command)
int &counter, OakUndoCommand parent_command)
{
std::vector<std::string> mutable_entries = entries;
@@ -336,11 +336,11 @@ void ProjectImportTask::validate_image_sequence(
void ProjectImportTask::add_item_to_folder(OakNodeFolder *folder,
OakNodeNode *item,
OakUndoCommand *command)
OakUndoCommand command)
{
OakUndoCommand *child =
OakUndoCommand child =
oaknode_command_create_folder_add_child(folder, item);
if (child) {
if (child.ctx) {
oakundo_command_multi_add_child(command, child);
}
}
+6 -6
View File
@@ -45,10 +45,10 @@ public:
/** Take ownership of the import command. After this call the task no
* longer owns (and will not free) the returned command. */
OakUndoCommand *take_command()
OakUndoCommand take_command()
{
OakUndoCommand *c = command_;
command_ = nullptr;
OakUndoCommand c = command_;
command_ = OakUndoCommand{};
return c;
}
@@ -87,14 +87,14 @@ protected:
private:
void import(OakNodeFolder *folder,
const std::vector<std::string> &entries, int &counter,
OakUndoCommand *parent_command);
OakUndoCommand parent_command);
void validate_image_sequence(OakNodeFootage *footage,
std::vector<std::string> &info_list,
size_t index);
void add_item_to_folder(OakNodeFolder *folder, OakNodeNode *item,
OakUndoCommand *command);
OakUndoCommand command);
static bool item_is_still_image_footage_only(OakNodeFootage *footage);
@@ -104,7 +104,7 @@ private:
static int64_t get_image_sequence_limit(const std::string &start_fn,
int64_t start, bool up);
OakUndoCommand *command_;
OakUndoCommand command_;
OakNodeFolder *folder_;
+16 -16
View File
@@ -192,12 +192,12 @@ bool LoadOTIOTask::run()
OakNodeNode *sequence_node = oaknode_sequence_as_node(sequence);
oaknode_project_add_node(project_, sequence_node);
OakUndoCommand *add_seq = oaknode_command_create_folder_add_child(
OakUndoCommand add_seq = oaknode_command_create_folder_add_child(
oaknode_project_root(project_), sequence_node);
if (add_seq) {
if (add_seq.ctx) {
oakundo_command_redo_now(add_seq);
oakundo_command_free(add_seq);
}
oakundo_command_free(&add_seq);
}
// Create a folder for this sequence's footage
OakNodeFolder *sequence_footage =
@@ -205,14 +205,14 @@ bool LoadOTIOTask::run()
if (sequence_footage) {
oaknode_node_set_label(oaknode_folder_as_node(sequence_footage),
timeline->name().c_str());
OakUndoCommand *add_folder =
OakUndoCommand add_folder =
oaknode_command_create_folder_add_child(
oaknode_project_root(project_),
oaknode_folder_as_node(sequence_footage));
if (add_folder) {
if (add_folder.ctx) {
oakundo_command_redo_now(add_folder);
oakundo_command_free(add_folder);
}
oakundo_command_free(&add_folder);
}
}
// Iterate through tracks
@@ -238,12 +238,12 @@ bool LoadOTIOTask::run()
OakNodeTrackList *track_list = nullptr;
oaknode_sequence_get_track_list(sequence, track_type,
&track_list);
OakUndoCommand *add_track =
OakUndoCommand add_track =
oaktimeline_add_track_command(track_list);
if (add_track) {
if (add_track.ctx) {
oakundo_command_redo_now(add_track);
oakundo_command_free(add_track);
}
oakundo_command_free(&add_track);
}
int count = 0;
oaknode_tracklist_get_track_count(track_list, &count);
@@ -403,15 +403,15 @@ bool LoadOTIOTask::run()
label.c_str());
if (sequence_footage) {
OakUndoCommand *add_footage =
OakUndoCommand add_footage =
oaknode_command_create_folder_add_child(
sequence_footage,
oaknode_footage_as_node(
probed_item));
if (add_footage) {
if (add_footage.ctx) {
oakundo_command_redo_now(add_footage);
oakundo_command_free(add_footage);
}
oakundo_command_free(&add_footage);
}
}
}
}
+7 -7
View File
@@ -164,9 +164,9 @@ TEST_F(OakTaskFixture, ImportDemoFootage)
OAKTASK_E_NOT_FOUND);
// The import command adds the footage to the folder; undo removes it
OakUndoCommand *cmd = oaktask_import_take_command(t);
ASSERT_NE(cmd, nullptr);
EXPECT_EQ(oaktask_import_take_command(t), nullptr);
OakUndoCommand cmd = oaktask_import_take_command(t);
ASSERT_NE(cmd.ctx, nullptr);
EXPECT_EQ(oaktask_import_take_command(t).ctx, nullptr);
EXPECT_EQ(oaknode_folder_child_count(folder), 0); // not yet redone
@@ -176,7 +176,7 @@ TEST_F(OakTaskFixture, ImportDemoFootage)
oakundo_command_undo_now(cmd);
EXPECT_EQ(oaknode_folder_child_count(folder), 0);
oakundo_command_free(cmd);
oakundo_command_free(&cmd);
oaktask_task_free(t);
EXPECT_EQ(oaktask_create_project_import(nullptr, project_, urls, 1),
@@ -385,11 +385,11 @@ TEST(OakTaskOTIO, SaveLoadRoundTrip)
OakNodeFolder *root = oaknode_project_root(project);
ASSERT_NE(root, nullptr);
OakUndoCommand *add_seq = oaknode_command_create_folder_add_child(
OakUndoCommand add_seq = oaknode_command_create_folder_add_child(
root, oaknode_sequence_as_node(sequence));
ASSERT_NE(add_seq, nullptr);
ASSERT_NE(add_seq.ctx, nullptr);
oakundo_command_redo_now(add_seq);
oakundo_command_free(add_seq);
oakundo_command_free(&add_seq);
std::string path =
(std::filesystem::temp_directory_path() / "oaktask_otio_test.otio")
+36 -40
View File
@@ -32,16 +32,12 @@
namespace
{
OakUndoCommand *wrap_command(olive::UndoCommand *command)
OakUndoCommand wrap_command(olive::UndoCommand *command)
{
if (!command) {
return NULL;
return OakUndoCommand{};
}
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand{command, true};
if (!handle) {
delete command;
}
return handle;
return oakundo_capi::make_command_handle(command, true);
}
olive::core::Rational rat(int64_t n, int64_t d)
@@ -56,73 +52,73 @@ olive::Timeline::MovementMode to_mode(int mode)
} // namespace
OakUndoCommand *oaktimeline_add_track_command(OakNodeTrackList *list)
OakUndoCommand oaktimeline_add_track_command(OakNodeTrackList *list)
{
if (!list) {
return NULL;
return OakUndoCommand{};
}
try {
return wrap_command(new olive::TimelineAddTrackCommand(list));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_remove_track_command(OakNodeTrack *track)
OakUndoCommand oaktimeline_remove_track_command(OakNodeTrack *track)
{
if (!track) {
return NULL;
return OakUndoCommand{};
}
try {
return wrap_command(new olive::TimelineRemoveTrackCommand(track));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_place_block_command(OakNodeTrackList *list,
OakUndoCommand oaktimeline_place_block_command(OakNodeTrackList *list,
int track_index,
OakNodeBlock *block,
int64_t in_num,
int64_t in_den)
{
if (!list || !block) {
return NULL;
return OakUndoCommand{};
}
try {
return wrap_command(new olive::TrackPlaceBlockCommand(
list, track_index, block, rat(in_num, in_den)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_replace_block_with_gap_command(
OakUndoCommand oaktimeline_replace_block_with_gap_command(
OakNodeTrack *track, OakNodeBlock *block)
{
if (!track || !block) {
return NULL;
return OakUndoCommand{};
}
try {
return wrap_command(
new olive::TrackReplaceBlockWithGapCommand(track, block));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_trim_command(OakNodeTrack *track,
OakUndoCommand oaktimeline_trim_command(OakNodeTrack *track,
OakNodeBlock *block,
int64_t new_length_num,
int64_t new_length_den, int mode)
{
if (!track || !block || (mode != OAKTIMELINE_MOVEMENT_TRIM_IN &&
mode != OAKTIMELINE_MOVEMENT_TRIM_OUT)) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -131,16 +127,16 @@ OakUndoCommand *oaktimeline_trim_command(OakNodeTrack *track,
rat(new_length_num, new_length_den),
to_mode(mode)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_split_command(OakNodeBlock *const *blocks,
OakUndoCommand oaktimeline_split_command(OakNodeBlock *const *blocks,
int count, int64_t point_num,
int64_t point_den)
{
if (!blocks || count <= 0) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -153,17 +149,17 @@ OakUndoCommand *oaktimeline_split_command(OakNodeBlock *const *blocks,
}
return wrap_command(multi);
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_split_preserving_links_command(
OakUndoCommand oaktimeline_split_preserving_links_command(
OakNodeBlock *const *blocks, int count, const int64_t *point_nums,
const int64_t *point_dens, int time_count)
{
if (!blocks || count <= 0 || !point_nums || !point_dens ||
time_count <= 0) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -176,18 +172,18 @@ OakUndoCommand *oaktimeline_split_preserving_links_command(
return wrap_command(new olive::BlockSplitPreservingLinksCommand(
block_vec, times));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_ripple_delete_gaps_command(
OakUndoCommand oaktimeline_ripple_delete_gaps_command(
OakNodeSequence *sequence, const int64_t *in_nums,
const int64_t *in_dens, const int64_t *out_nums,
const int64_t *out_dens, OakNodeTrack *const *tracks, int range_count)
{
if (!sequence || !in_nums || !in_dens || !out_nums || !out_dens ||
!tracks || range_count <= 0) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -203,17 +199,17 @@ OakUndoCommand *oaktimeline_ripple_delete_gaps_command(
new olive::TimelineRippleDeleteGapsAtRegionsCommand(sequence,
regions));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_slide_command(
OakUndoCommand oaktimeline_slide_command(
OakNodeTrack *track, OakNodeBlock *const *blocks, int block_count,
OakNodeBlock *in_adjacent, OakNodeBlock *out_adjacent,
int64_t movement_num, int64_t movement_den)
{
if (!track || !blocks || block_count <= 0) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -222,16 +218,16 @@ OakUndoCommand *oaktimeline_slide_command(
track, block_vec, in_adjacent, out_adjacent,
rat(movement_num, movement_den)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_ripple_remove_area_command(
OakUndoCommand oaktimeline_ripple_remove_area_command(
OakNodeTrack *track, int64_t in_num, int64_t in_den, int64_t out_num,
int64_t out_den)
{
if (!track) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -239,18 +235,18 @@ OakUndoCommand *oaktimeline_ripple_remove_area_command(
track, olive::core::TimeRange(rat(in_num, in_den),
rat(out_num, out_den))));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_insert_gaps_command(OakNodeTrackList *list,
OakUndoCommand oaktimeline_insert_gaps_command(OakNodeTrackList *list,
int64_t point_num,
int64_t point_den,
int64_t length_num,
int64_t length_den)
{
if (!list) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -258,6 +254,6 @@ OakUndoCommand *oaktimeline_insert_gaps_command(OakNodeTrackList *list,
new olive::TrackListInsertGaps(list, rat(point_num, point_den),
rat(length_num, length_den)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
+15 -19
View File
@@ -43,16 +43,12 @@ OakTimelineMarkerList *wrap(olive::TimelineMarkerList *l)
return reinterpret_cast<OakTimelineMarkerList *>(l);
}
OakUndoCommand *wrap_command(olive::UndoCommand *command)
OakUndoCommand wrap_command(olive::UndoCommand *command)
{
if (!command) {
return NULL;
return OakUndoCommand{};
}
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand{command, true};
if (!handle) {
delete command;
}
return handle;
return oakundo_capi::make_command_handle(command, true);
}
olive::core::Rational rat(int n, int d)
@@ -130,12 +126,12 @@ int oaktimeline_marker_at(const OakTimelineMarkerList *list, int index,
return needed;
}
OakUndoCommand *oaktimeline_marker_add_command(
OakUndoCommand oaktimeline_marker_add_command(
OakTimelineMarkerList *list, int in_num, int in_den, int out_num,
int out_den, const char *name, int color)
{
if (!list) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -145,32 +141,32 @@ OakUndoCommand *oaktimeline_marker_add_command(
rat(int(out_num), int(out_den))),
name ? name : "", color));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_marker_remove_at_command(
OakUndoCommand oaktimeline_marker_remove_at_command(
OakTimelineMarkerList *list, int index)
{
olive::TimelineMarker *m = marker_at(list, index);
if (!m) {
return NULL;
return OakUndoCommand{};
}
try {
return wrap_command(new olive::MarkerRemoveCommand(m, impl(list)));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_marker_set_time_command(
OakUndoCommand oaktimeline_marker_set_time_command(
OakTimelineMarkerList *list, int index, int in_num, int in_den,
int out_num, int out_den)
{
olive::TimelineMarker *m = marker_at(list, index);
if (!m) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -178,16 +174,16 @@ OakUndoCommand *oaktimeline_marker_set_time_command(
m, olive::core::TimeRange(rat(int(in_num), int(in_den)),
rat(int(out_num), int(out_den)))));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_marker_set_props_command(
OakUndoCommand oaktimeline_marker_set_props_command(
OakTimelineMarkerList *list, int index, int color, const char *name)
{
olive::TimelineMarker *m = marker_at(list, index);
if (!m || (color < 0 && !name)) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -202,7 +198,7 @@ OakUndoCommand *oaktimeline_marker_set_props_command(
}
return wrap_command(new olive::MarkerChangeNameCommand(m, name));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
+9 -13
View File
@@ -39,16 +39,12 @@ const olive::TimelineWorkArea *impl(const OakTimelineWorkArea *h)
return reinterpret_cast<const olive::TimelineWorkArea *>(h);
}
OakUndoCommand *wrap_command(olive::UndoCommand *command)
OakUndoCommand wrap_command(olive::UndoCommand *command)
{
if (!command) {
return NULL;
return OakUndoCommand{};
}
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand{command, true};
if (!handle) {
delete command;
}
return handle;
return oakundo_capi::make_command_handle(command, true);
}
olive::core::Rational rat(int64_t n, int64_t d)
@@ -113,13 +109,13 @@ int oaktimeline_workarea_set_range(OakTimelineWorkArea *w, int in_num,
}
}
OakUndoCommand *oaktimeline_workarea_set_range_command(
OakUndoCommand oaktimeline_workarea_set_range_command(
OakTimelineWorkArea *w, int in_num, int in_den, int out_num,
int out_den, int old_in_num, int old_in_den, int old_out_num,
int old_out_den)
{
if (!w) {
return NULL;
return OakUndoCommand{};
}
try {
@@ -129,22 +125,22 @@ OakUndoCommand *oaktimeline_workarea_set_range_command(
return wrap_command(
new olive::WorkareaSetRangeCommand(impl(w), range, old_range));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oaktimeline_workarea_set_enabled_command(
OakUndoCommand oaktimeline_workarea_set_enabled_command(
OakTimelineWorkArea *w, int enabled)
{
if (!w) {
return NULL;
return OakUndoCommand{};
}
try {
return wrap_command(
new olive::WorkareaSetEnabledCommand(impl(w), enabled != 0));
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
+17 -12
View File
@@ -40,29 +40,29 @@ inline bool node_can_be_removed(OakNodeBlock *b)
return node_can_be_removed(oaknode_block_as_node(b));
}
inline OakUndoCommand *create_remove_command(OakNodeNode *n)
inline OakUndoCommand create_remove_command(OakNodeNode *n)
{
return oaknode_command_create_remove_node(n);
}
inline OakUndoCommand *create_remove_command(OakNodeBlock *b)
inline OakUndoCommand create_remove_command(OakNodeBlock *b)
{
return oaknode_command_create_remove_node(oaknode_block_as_node(b));
}
inline OakUndoCommand *create_and_run_remove_command(OakNodeNode *n)
inline OakUndoCommand create_and_run_remove_command(OakNodeNode *n)
{
OakUndoCommand *command = create_remove_command(n);
OakUndoCommand command = create_remove_command(n);
oakundo_command_redo_now(command);
return command;
}
inline OakUndoCommand *create_and_run_remove_command(OakNodeBlock *b)
inline OakUndoCommand create_and_run_remove_command(OakNodeBlock *b)
{
return create_and_run_remove_command(oaknode_block_as_node(b));
}
inline void free_remove_command(OakUndoCommand *command)
inline void free_command_handle(OakUndoCommand *command)
{
oakundo_command_free(command);
}
@@ -73,35 +73,40 @@ inline void free_remove_command(OakUndoCommand *command)
*/
class CHandleCommandWrapper : public UndoCommand {
public:
CHandleCommandWrapper(OakUndoCommand *command)
CHandleCommandWrapper(OakUndoCommand command)
: command_(command)
{
}
virtual ~CHandleCommandWrapper() override
{
if (command_) {
oakundo_command_free(command_);
if (command_.ctx) {
oakundo_command_free(&command_);
}
}
bool is_valid() const
{
return command_.ctx != nullptr;
}
protected:
virtual void redo() override
{
if (command_) {
if (command_.ctx) {
oakundo_command_redo_now(command_);
}
}
virtual void undo() override
{
if (command_) {
if (command_.ctx) {
oakundo_command_undo_now(command_);
}
}
private:
OakUndoCommand *command_;
OakUndoCommand command_;
};
}
+20 -20
View File
@@ -45,9 +45,9 @@ const char *k_merge_blend_input = "blend_in";
const char *k_math_param_a_input = "param_a_in";
const char *k_math_param_b_input = "param_b_in";
void add_multi_child(OakUndoCommand *multi, OakUndoCommand *child)
void add_multi_child(OakUndoCommand multi, OakUndoCommand child)
{
if (multi && child) {
if (multi.ctx && child.ctx) {
oakundo_command_multi_add_child(multi, child);
}
}
@@ -116,7 +116,7 @@ TimelineAddTrackCommand::TimelineAddTrackCommand(
: timeline_(timeline)
, track_(nullptr)
, merge_(nullptr)
, position_command_(nullptr)
, position_command_({})
, automerge_tracks_(automerge_tracks)
, track_orphaned_(false)
, merge_orphaned_(false)
@@ -164,8 +164,8 @@ TimelineAddTrackCommand::TimelineAddTrackCommand(
TimelineAddTrackCommand::~TimelineAddTrackCommand()
{
if (position_command_) {
oakundo_command_free(position_command_);
if (position_command_.ctx) {
oakundo_command_free(&position_command_);
}
if (track_orphaned_ && track_) {
oaknode_track_free(track_);
@@ -221,7 +221,7 @@ void TimelineAddTrackCommand::redo()
position_factor = -position_factor;
}
bool create_pos_command =
(!position_command_ && (type == OAKNODE_TRACK_TYPE_VIDEO ||
(!position_command_.ctx && (type == OAKNODE_TRACK_TYPE_VIDEO ||
type == OAKNODE_TRACK_TYPE_AUDIO));
if (create_pos_command) {
position_command_ = oakundo_command_init_multi();
@@ -250,19 +250,19 @@ void TimelineAddTrackCommand::redo()
}
oaknode_node_connect(track_node, merge_, blend_input_.c_str());
if (create_pos_command && position_command_) {
if (create_pos_command && position_command_.ctx) {
double sx = 0, sy = 0;
oaknode_node_get_context_position(sequence_node, sequence_node,
&sx, &sy, NULL);
OakUndoCommand *child = nullptr;
OakUndoCommand child = {};
if (oaknode_node_set_context_position_undoable(
track_node, sequence_node, sx - 1,
sy - position_factor, 0,
&child) == OAKNODE_OK) {
add_multi_child(position_command_, child);
}
child = nullptr;
child = OakUndoCommand{};
if (oaknode_node_set_context_position_undoable(
merge_, sequence_node, sx, sy, 0, &child) == OAKNODE_OK) {
add_multi_child(position_command_, child);
@@ -285,14 +285,14 @@ void TimelineAddTrackCommand::redo()
oaknode_node_connect(track_node, sequence_node,
direct_input_.c_str());
if (create_pos_command && position_command_) {
if (create_pos_command && position_command_.ctx) {
// Just position directly next to the context node
double sx = 0, sy = 0;
oaknode_node_get_context_position(sequence_node,
sequence_node, &sx, &sy,
NULL);
OakUndoCommand *child = nullptr;
OakUndoCommand child = {};
if (oaknode_node_set_context_position_undoable(
track_node, sequence_node, sx - 1,
sy + position_factor, 0,
@@ -304,14 +304,14 @@ void TimelineAddTrackCommand::redo()
}
// Run position command if we created one
if (position_command_) {
if (position_command_.ctx) {
oakundo_command_redo_now(position_command_);
}
}
void TimelineAddTrackCommand::undo()
{
if (position_command_) {
if (position_command_.ctx) {
oakundo_command_undo_now(position_command_);
}
@@ -371,8 +371,8 @@ void TimelineAddTrackCommand::undo()
//
TransitionRemoveCommand::~TransitionRemoveCommand()
{
if (remove_command_) {
free_remove_command(remove_command_);
if (remove_command_.ctx) {
free_command_handle(&remove_command_);
}
}
@@ -409,7 +409,7 @@ void TransitionRemoveCommand::redo()
oaknode_track_ripple_remove_block(track_, block_);
if (remove_from_graph_) {
if (!remove_command_) {
if (!remove_command_.ctx) {
remove_command_ = create_remove_command(block_);
}
@@ -789,8 +789,8 @@ void TrackReplaceBlockWithGapCommand::create_remove_transition_command_if_necess
//
TimelineRemoveTrackCommand::~TimelineRemoveTrackCommand()
{
if (remove_command_) {
free_remove_command(remove_command_);
if (remove_command_.ctx) {
free_command_handle(&remove_command_);
}
}
@@ -996,7 +996,7 @@ void TimelineAddDefaultTransitionCommand::add_transition(
new TrackInsertBlockAfterCommand(t, transition, insert_after));
// Connect
OakUndoCommand *edge_command = nullptr;
OakUndoCommand edge_command = {};
switch (mode) {
case k_in:
if (oaknode_node_connect_undoable(
@@ -1015,7 +1015,7 @@ void TimelineAddDefaultTransitionCommand::add_transition(
}
/* fall through */
case k_out:
edge_command = nullptr;
edge_command = OakUndoCommand{};
if (oaknode_node_connect_undoable(
oaknode_block_as_node(c), p,
OAKNODE_TRANSITION_OUT_BLOCK_INPUT,
+5 -5
View File
@@ -135,7 +135,7 @@ private:
std::string direct_input_;
OakUndoCommand *position_command_;
OakUndoCommand position_command_;
bool automerge_tracks_;
@@ -151,7 +151,7 @@ public:
: track_(track)
, list_(nullptr)
, index_(0)
, remove_command_(nullptr)
, remove_command_({})
{
}
@@ -171,7 +171,7 @@ private:
int index_;
OakUndoCommand *remove_command_;
OakUndoCommand remove_command_;
};
class TransitionRemoveCommand : public UndoCommand {
@@ -182,7 +182,7 @@ public:
, out_block_(nullptr)
, in_block_(nullptr)
, remove_from_graph_(remove_from_graph)
, remove_command_(nullptr)
, remove_command_({})
{
}
@@ -202,7 +202,7 @@ private:
OakNodeBlock *in_block_;
bool remove_from_graph_;
OakUndoCommand *remove_command_;
OakUndoCommand remove_command_;
};
class TrackReplaceBlockWithGapCommand : public UndoCommand {
+12 -12
View File
@@ -33,8 +33,8 @@ namespace olive
//
BlockTrimCommand::~BlockTrimCommand()
{
if (deleted_adjacent_command_) {
free_remove_command(deleted_adjacent_command_);
if (deleted_adjacent_command_.ctx) {
free_command_handle(&deleted_adjacent_command_);
}
if (adjacent_orphaned_ && adjacent_) {
oaknode_block_free(adjacent_);
@@ -68,7 +68,7 @@ void BlockTrimCommand::redo()
// It no longer inputs/outputs anything, remove it
if (remove_block_from_graph_ && node_can_be_removed(adjacent_)) {
if (!deleted_adjacent_command_) {
if (!deleted_adjacent_command_.ctx) {
deleted_adjacent_command_ =
create_and_run_remove_command(adjacent_);
} else {
@@ -102,7 +102,7 @@ void BlockTrimCommand::undo()
adjacent_orphaned_ = true;
} else {
if (we_removed_adjacent_) {
if (deleted_adjacent_command_) {
if (deleted_adjacent_command_.ctx) {
// We deleted adjacent, restore it now
oakundo_command_undo_now(deleted_adjacent_command_);
}
@@ -188,11 +188,11 @@ void BlockTrimCommand::prepare()
//
TrackSlideCommand::~TrackSlideCommand()
{
if (in_adjacent_remove_command_) {
free_remove_command(in_adjacent_remove_command_);
if (in_adjacent_remove_command_.ctx) {
free_command_handle(&in_adjacent_remove_command_);
}
if (out_adjacent_remove_command_) {
free_remove_command(out_adjacent_remove_command_);
if (out_adjacent_remove_command_.ctx) {
free_command_handle(&out_adjacent_remove_command_);
}
if (in_adjacent_orphaned_ && in_adjacent_) {
oaknode_block_free(in_adjacent_);
@@ -216,7 +216,7 @@ void TrackSlideCommand::redo()
oaknode_track_ripple_remove_block(track_, in_adjacent_);
if (node_can_be_removed(in_adjacent_)) {
if (!in_adjacent_remove_command_) {
if (!in_adjacent_remove_command_.ctx) {
in_adjacent_remove_command_ =
create_remove_command(in_adjacent_);
}
@@ -244,7 +244,7 @@ void TrackSlideCommand::redo()
oaknode_track_ripple_remove_block(track_, out_adjacent_);
if (node_can_be_removed(out_adjacent_)) {
if (!out_adjacent_remove_command_) {
if (!out_adjacent_remove_command_.ctx) {
out_adjacent_remove_command_ =
create_remove_command(out_adjacent_);
}
@@ -270,7 +270,7 @@ void TrackSlideCommand::undo()
block_remove_from_graph(in_adjacent_, track_);
in_adjacent_orphaned_ = true;
} else if (we_removed_in_adjacent_) {
if (in_adjacent_remove_command_) {
if (in_adjacent_remove_command_.ctx) {
// We removed this, so we can restore it now
oakundo_command_undo_now(in_adjacent_remove_command_);
}
@@ -290,7 +290,7 @@ void TrackSlideCommand::undo()
block_remove_from_graph(out_adjacent_, track_);
out_adjacent_orphaned_ = true;
} else if (we_removed_out_adjacent_) {
if (out_adjacent_remove_command_) {
if (out_adjacent_remove_command_.ctx) {
oakundo_command_undo_now(out_adjacent_remove_command_);
}
+6 -6
View File
@@ -56,7 +56,7 @@ public:
, block_(block)
, new_length_(new_length)
, mode_(mode)
, deleted_adjacent_command_(nullptr)
, deleted_adjacent_command_({})
, trim_is_a_roll_edit_(false)
, remove_block_from_graph_(true)
, doing_nothing_(false)
@@ -109,7 +109,7 @@ private:
bool needs_adjacent_;
bool we_created_adjacent_;
bool we_removed_adjacent_;
OakUndoCommand *deleted_adjacent_command_;
OakUndoCommand deleted_adjacent_command_;
bool trim_is_a_roll_edit_;
bool remove_block_from_graph_;
@@ -130,12 +130,12 @@ public:
, we_created_in_adjacent_(false)
, we_removed_in_adjacent_(false)
, in_adjacent_(in_adjacent)
, in_adjacent_remove_command_(nullptr)
, in_adjacent_remove_command_({})
, in_adjacent_orphaned_(false)
, we_created_out_adjacent_(false)
, we_removed_out_adjacent_(false)
, out_adjacent_(out_adjacent)
, out_adjacent_remove_command_(nullptr)
, out_adjacent_remove_command_({})
, out_adjacent_orphaned_(false)
{
}
@@ -157,12 +157,12 @@ private:
bool we_created_in_adjacent_;
bool we_removed_in_adjacent_;
OakNodeBlock *in_adjacent_;
OakUndoCommand *in_adjacent_remove_command_;
OakUndoCommand in_adjacent_remove_command_;
bool in_adjacent_orphaned_;
bool we_created_out_adjacent_;
bool we_removed_out_adjacent_;
OakNodeBlock *out_adjacent_;
OakUndoCommand *out_adjacent_remove_command_;
OakUndoCommand out_adjacent_remove_command_;
bool out_adjacent_orphaned_;
};
+3 -3
View File
@@ -49,8 +49,8 @@ TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(
TrackRippleRemoveAreaCommand::~TrackRippleRemoveAreaCommand()
{
delete splice_split_command_;
for (OakUndoCommand *c : remove_block_commands_) {
free_remove_command(c);
for (OakUndoCommand &c : remove_block_commands_) {
free_command_handle(&c);
}
}
@@ -170,7 +170,7 @@ void TrackRippleRemoveAreaCommand::redo()
}
}
for (OakUndoCommand *c : remove_block_commands_) {
for (OakUndoCommand &c : remove_block_commands_) {
oakundo_command_redo_now(c);
}
}
+1 -1
View File
@@ -106,7 +106,7 @@ private:
bool allow_splitting_gaps_;
BlockSplitCommand *splice_split_command_;
std::vector<OakUndoCommand *> remove_block_commands_;
std::vector<OakUndoCommand > remove_block_commands_;
};
class TrackListRippleRemoveAreaCommand : public UndoCommand {
+4 -4
View File
@@ -83,8 +83,8 @@ private:
//
BlockSplitCommand::~BlockSplitCommand()
{
if (reconnect_tree_command_) {
oakundo_command_free(reconnect_tree_command_);
if (reconnect_tree_command_.ctx) {
oakundo_command_free(&reconnect_tree_command_);
}
}
@@ -110,7 +110,7 @@ void BlockSplitCommand::redo()
assert(point_ > block_in && point_ < block_out);
if (reconnect_tree_command_) {
if (reconnect_tree_command_.ctx) {
oakundo_command_redo_now(reconnect_tree_command_);
}
@@ -193,7 +193,7 @@ void BlockSplitCommand::undo()
oaknode_track_ripple_remove_block(track, new_block_);
// If we ran a reconnect command, disconnect now
if (reconnect_tree_command_) {
if (reconnect_tree_command_.ctx) {
oakundo_command_undo_now(reconnect_tree_command_);
}
}
+2 -2
View File
@@ -48,7 +48,7 @@ public:
: block_(block)
, new_block_(nullptr)
, point_(point)
, reconnect_tree_command_(nullptr)
, reconnect_tree_command_({})
, moved_transition_(nullptr)
{
}
@@ -77,7 +77,7 @@ private:
Rational old_length_;
Rational point_;
OakUndoCommand *reconnect_tree_command_;
OakUndoCommand reconnect_tree_command_;
OakNodeBlock *moved_transition_;
std::string moved_transition_input_;
+68 -60
View File
@@ -80,11 +80,11 @@ TEST_F(TimelineSequenceFixture, MarkerAddCountAtRemove)
EXPECT_EQ(oaktimeline_marker_count(list, nullptr),
OAKTIMELINE_E_INVALID);
OakUndoCommand *cmd =
OakUndoCommand cmd =
oaktimeline_marker_add_command(list, 1, 2, 3, 4, "mark", 5);
ASSERT_NE(cmd, nullptr);
ASSERT_NE(cmd.ctx, nullptr);
oakundo_command_redo_now(cmd);
oakundo_command_free(cmd);
oakundo_command_free(&cmd);
EXPECT_EQ(oaktimeline_marker_count(list, &count), OAKTIMELINE_OK);
ASSERT_EQ(count, 1);
@@ -108,15 +108,15 @@ TEST_F(TimelineSequenceFixture, MarkerAddCountAtRemove)
&out_d, &color, name, sizeof(name)),
OAKTIMELINE_E_INVALID);
OakUndoCommand *rm = oaktimeline_marker_remove_at_command(list, 0);
ASSERT_NE(rm, nullptr);
OakUndoCommand rm = oaktimeline_marker_remove_at_command(list, 0);
ASSERT_NE(rm.ctx, nullptr);
oakundo_command_redo_now(rm);
oakundo_command_free(rm);
oakundo_command_free(&rm);
EXPECT_EQ(oaktimeline_marker_count(list, &count), OAKTIMELINE_OK);
EXPECT_EQ(count, 0);
EXPECT_EQ(oaktimeline_marker_remove_at_command(list, 4), nullptr);
EXPECT_EQ(oaktimeline_marker_remove_at_command(list, 4).ctx, nullptr);
}
TEST_F(TimelineSequenceFixture, MarkerSetTimeAndPropsUndo)
@@ -124,15 +124,15 @@ TEST_F(TimelineSequenceFixture, MarkerSetTimeAndPropsUndo)
OakTimelineMarkerList *list = oaktimeline_marker_list_of(node_);
ASSERT_NE(list, nullptr);
OakUndoCommand *add =
OakUndoCommand add =
oaktimeline_marker_add_command(list, 0, 1, 1, 1, "a", 1);
ASSERT_NE(add, nullptr);
ASSERT_NE(add.ctx, nullptr);
oakundo_command_redo_now(add);
oakundo_command_free(add);
oakundo_command_free(&add);
OakUndoCommand *set_time =
OakUndoCommand set_time =
oaktimeline_marker_set_time_command(list, 0, 10, 1, 20, 1);
ASSERT_NE(set_time, nullptr);
ASSERT_NE(set_time.ctx, nullptr);
oakundo_command_redo_now(set_time);
int in_n = 0;
@@ -146,13 +146,13 @@ TEST_F(TimelineSequenceFixture, MarkerSetTimeAndPropsUndo)
NULL, NULL, 0),
0);
EXPECT_EQ(in_n, 0);
oakundo_command_free(set_time);
oakundo_command_free(&set_time);
OakUndoCommand *props =
OakUndoCommand props =
oaktimeline_marker_set_props_command(list, 0, 7, "renamed");
ASSERT_NE(props, nullptr);
ASSERT_NE(props.ctx, nullptr);
oakundo_command_redo_now(props);
oakundo_command_free(props);
oakundo_command_free(&props);
int color = 0;
char name[32];
@@ -162,9 +162,11 @@ TEST_F(TimelineSequenceFixture, MarkerSetTimeAndPropsUndo)
EXPECT_EQ(color, 7);
EXPECT_STREQ(name, "renamed");
EXPECT_EQ(oaktimeline_marker_set_props_command(list, 0, -1, NULL),
EXPECT_EQ(oaktimeline_marker_set_props_command(list, 0, -1, NULL)
.ctx,
nullptr);
EXPECT_EQ(oaktimeline_marker_set_time_command(list, 9, 0, 1, 1, 1),
EXPECT_EQ(oaktimeline_marker_set_time_command(list, 9, 0, 1, 1, 1)
.ctx,
nullptr);
}
@@ -173,11 +175,11 @@ TEST_F(TimelineSequenceFixture, MarkerListXmlRoundTrip)
OakTimelineMarkerList *list = oaktimeline_marker_list_of(node_);
ASSERT_NE(list, nullptr);
OakUndoCommand *add =
OakUndoCommand add =
oaktimeline_marker_add_command(list, 1, 3, 2, 3, "xml", 4);
ASSERT_NE(add, nullptr);
ASSERT_NE(add.ctx, nullptr);
oakundo_command_redo_now(add);
oakundo_command_free(add);
oakundo_command_free(&add);
OakXmlWriter writer = oakcommon_xml_writer_init();
ASSERT_NE(writer.ctx, nullptr);
@@ -265,9 +267,9 @@ TEST_F(TimelineSequenceFixture, WorkareaUndoCommands)
OakTimelineWorkArea *w = oaktimeline_workarea_of(node_);
ASSERT_NE(w, nullptr);
OakUndoCommand *range_cmd = oaktimeline_workarea_set_range_command(
OakUndoCommand range_cmd = oaktimeline_workarea_set_range_command(
w, 1, 2, 1, 1, 0, 1, 1, 1);
ASSERT_NE(range_cmd, nullptr);
ASSERT_NE(range_cmd.ctx, nullptr);
oakundo_command_redo_now(range_cmd);
int in_n = 0, out_n = 0;
@@ -280,11 +282,11 @@ TEST_F(TimelineSequenceFixture, WorkareaUndoCommands)
EXPECT_EQ(oaktimeline_workarea_get(w, &in_n, NULL, &out_n, NULL, NULL),
OAKTIMELINE_OK);
EXPECT_EQ(in_n, 0);
oakundo_command_free(range_cmd);
oakundo_command_free(&range_cmd);
OakUndoCommand *enable_cmd =
OakUndoCommand enable_cmd =
oaktimeline_workarea_set_enabled_command(w, 1);
ASSERT_NE(enable_cmd, nullptr);
ASSERT_NE(enable_cmd.ctx, nullptr);
oakundo_command_redo_now(enable_cmd);
int enabled = 0;
@@ -298,12 +300,13 @@ TEST_F(TimelineSequenceFixture, WorkareaUndoCommands)
&enabled),
OAKTIMELINE_OK);
EXPECT_EQ(enabled, 0);
oakundo_command_free(enable_cmd);
oakundo_command_free(&enable_cmd);
EXPECT_EQ(oaktimeline_workarea_set_range_command(nullptr, 0, 1, 1, 1,
0, 1, 1, 1),
0, 1, 1, 1)
.ctx,
nullptr);
EXPECT_EQ(oaktimeline_workarea_set_enabled_command(nullptr, 1),
EXPECT_EQ(oaktimeline_workarea_set_enabled_command(nullptr, 1).ctx,
nullptr);
}
@@ -381,8 +384,8 @@ TEST_F(TimelineSequenceFixture, AddAndRemoveTrackCommands)
EXPECT_EQ(oaknode_tracklist_get_track_count(list, &count), OAKNODE_OK);
const int before = count;
OakUndoCommand *add = oaktimeline_add_track_command(list);
ASSERT_NE(add, nullptr);
OakUndoCommand add = oaktimeline_add_track_command(list);
ASSERT_NE(add.ctx, nullptr);
oakundo_command_redo_now(add);
EXPECT_EQ(oaknode_tracklist_get_track_count(list, &count), OAKNODE_OK);
@@ -393,8 +396,8 @@ TEST_F(TimelineSequenceFixture, AddAndRemoveTrackCommands)
OAKNODE_OK);
ASSERT_NE(track, nullptr);
OakUndoCommand *rm = oaktimeline_remove_track_command(track);
ASSERT_NE(rm, nullptr);
OakUndoCommand rm = oaktimeline_remove_track_command(track);
ASSERT_NE(rm.ctx, nullptr);
oakundo_command_redo_now(rm);
EXPECT_EQ(oaknode_tracklist_get_track_count(list, &count), OAKNODE_OK);
@@ -408,11 +411,11 @@ TEST_F(TimelineSequenceFixture, AddAndRemoveTrackCommands)
EXPECT_EQ(oaknode_tracklist_get_track_count(list, &count), OAKNODE_OK);
EXPECT_EQ(count, before);
oakundo_command_free(add);
oakundo_command_free(rm);
oakundo_command_free(&add);
oakundo_command_free(&rm);
EXPECT_EQ(oaktimeline_add_track_command(nullptr), nullptr);
EXPECT_EQ(oaktimeline_remove_track_command(nullptr), nullptr);
EXPECT_EQ(oaktimeline_add_track_command(nullptr).ctx, nullptr);
EXPECT_EQ(oaktimeline_remove_track_command(nullptr).ctx, nullptr);
}
TEST_F(TimelineSequenceFixture, PlaceTrimSplitRemoveAreaCommands)
@@ -437,9 +440,9 @@ TEST_F(TimelineSequenceFixture, PlaceTrimSplitRemoveAreaCommands)
oaknode_block_as_node(clip)),
OAKNODE_OK);
OakUndoCommand *place =
OakUndoCommand place =
oaktimeline_place_block_command(list, 0, clip, 0, 1);
ASSERT_NE(place, nullptr);
ASSERT_NE(place.ctx, nullptr);
oakundo_command_redo_now(place);
int block_count = 0;
@@ -448,9 +451,9 @@ TEST_F(TimelineSequenceFixture, PlaceTrimSplitRemoveAreaCommands)
ASSERT_EQ(block_count, 1);
// Trim out to length 4
OakUndoCommand *trim = oaktimeline_trim_command(
OakUndoCommand trim = oaktimeline_trim_command(
track, clip, 4, 1, OAKTIMELINE_MOVEMENT_TRIM_OUT);
ASSERT_NE(trim, nullptr);
ASSERT_NE(trim.ctx, nullptr);
oakundo_command_redo_now(trim);
int n = 0, d = 0;
@@ -460,13 +463,13 @@ TEST_F(TimelineSequenceFixture, PlaceTrimSplitRemoveAreaCommands)
oakundo_command_undo_now(trim);
EXPECT_EQ(oaknode_block_get_length(clip, &n, &d), OAKNODE_OK);
EXPECT_EQ(n, 10);
oakundo_command_free(trim);
oakundo_command_free(&trim);
// Split at 5: two blocks of 5
OakNodeBlock *blocks[] = { clip };
OakUndoCommand *split =
OakUndoCommand split =
oaktimeline_split_command(blocks, 1, 5, 1);
ASSERT_NE(split, nullptr);
ASSERT_NE(split.ctx, nullptr);
oakundo_command_redo_now(split);
EXPECT_EQ(oaknode_track_get_block_count(track, &block_count),
@@ -477,12 +480,12 @@ TEST_F(TimelineSequenceFixture, PlaceTrimSplitRemoveAreaCommands)
EXPECT_EQ(oaknode_track_get_block_count(track, &block_count),
OAKNODE_OK);
ASSERT_EQ(block_count, 1);
oakundo_command_free(split);
oakundo_command_free(&split);
// Ripple remove [3..5] then undo
OakUndoCommand *remove_area =
OakUndoCommand remove_area =
oaktimeline_ripple_remove_area_command(track, 3, 1, 5, 1);
ASSERT_NE(remove_area, nullptr);
ASSERT_NE(remove_area.ctx, nullptr);
oakundo_command_redo_now(remove_area);
// Removing [3..5] from [0..10] splices it into [0..3] + [5..10]
@@ -501,19 +504,21 @@ TEST_F(TimelineSequenceFixture, PlaceTrimSplitRemoveAreaCommands)
oakundo_command_undo_now(remove_area);
EXPECT_EQ(oaknode_block_get_length(clip, &n, &d), OAKNODE_OK);
EXPECT_EQ(n, 10);
oakundo_command_free(remove_area);
oakundo_command_free(&remove_area);
oakundo_command_undo_now(place);
EXPECT_EQ(oaknode_track_get_block_count(track, &block_count),
OAKNODE_OK);
EXPECT_EQ(block_count, 0);
oakundo_command_free(place);
oakundo_command_free(&place);
EXPECT_EQ(oaktimeline_place_block_command(nullptr, 0, clip, 0, 1),
EXPECT_EQ(oaktimeline_place_block_command(nullptr, 0, clip, 0, 1)
.ctx,
nullptr);
EXPECT_EQ(oaktimeline_trim_command(track, clip, 1, 1, 99), nullptr);
EXPECT_EQ(oaktimeline_split_command(blocks, 0, 1, 1), nullptr);
EXPECT_EQ(oaktimeline_ripple_remove_area_command(nullptr, 0, 1, 1, 1),
EXPECT_EQ(oaktimeline_trim_command(track, clip, 1, 1, 99).ctx, nullptr);
EXPECT_EQ(oaktimeline_split_command(blocks, 0, 1, 1).ctx, nullptr);
EXPECT_EQ(oaktimeline_ripple_remove_area_command(nullptr, 0, 1, 1, 1)
.ctx,
nullptr);
}
@@ -550,9 +555,9 @@ TEST_F(TimelineSequenceFixture, ReplaceWithGapCommand)
OAKNODE_OK);
EXPECT_EQ(oaknode_track_append_block(track, clip2), OAKNODE_OK);
OakUndoCommand *replace =
OakUndoCommand replace =
oaktimeline_replace_block_with_gap_command(track, clip);
ASSERT_NE(replace, nullptr);
ASSERT_NE(replace.ctx, nullptr);
oakundo_command_redo_now(replace);
int block_count = 0;
@@ -569,9 +574,10 @@ TEST_F(TimelineSequenceFixture, ReplaceWithGapCommand)
oakundo_command_undo_now(replace);
EXPECT_EQ(oaknode_track_get_block_at(track, 0, &first), OAKNODE_OK);
EXPECT_EQ(first, clip);
oakundo_command_free(replace);
oakundo_command_free(&replace);
EXPECT_EQ(oaktimeline_replace_block_with_gap_command(nullptr, clip),
EXPECT_EQ(oaktimeline_replace_block_with_gap_command(nullptr, clip)
.ctx,
nullptr);
EXPECT_EQ(oaknode_track_ripple_remove_block(track, clip), OAKNODE_OK);
@@ -582,18 +588,20 @@ TEST_F(TimelineSequenceFixture, SlideAndInsertGapsAndRippleDeleteGapsFactories)
{
OakNodeBlock *clip = oaknode_block_clip_create();
EXPECT_EQ(oaktimeline_slide_command(nullptr, &clip, 1, nullptr,
nullptr, 1, 1),
nullptr, 1, 1)
.ctx,
nullptr);
OakNodeTrackList *list = nullptr;
ASSERT_EQ(oaknode_sequence_get_track_list(
sequence_, OAKNODE_TRACK_TYPE_VIDEO, &list),
OAKNODE_OK);
EXPECT_EQ(oaktimeline_insert_gaps_command(nullptr, 0, 1, 1, 1),
EXPECT_EQ(oaktimeline_insert_gaps_command(nullptr, 0, 1, 1, 1).ctx,
nullptr);
EXPECT_EQ(oaktimeline_ripple_delete_gaps_command(
sequence_, nullptr, nullptr, nullptr, nullptr, nullptr, 0),
sequence_, nullptr, nullptr, nullptr, nullptr, nullptr, 0)
.ctx,
nullptr);
oaknode_block_free(clip);
+86 -7
View File
@@ -21,21 +21,100 @@
#ifndef OAK_UNDO_COMMANDHANDLE_H
#define OAK_UNDO_COMMANDHANDLE_H
#include <atomic>
#include "undo/undocommand.h"
#include "../src/undocommand.h"
/**
* @brief Internal layout of the OakUndoCommand handle, shared between the
* c_api translation units.
* @brief Internal control block behind OakUndoCommand, shared between
* the c_api translation units.
*
* `owned` is true for handles created by oakundo_command_init() /
* oakundo_command_init_multi() and false for borrowed wrappers handed out
* by oakundo_command_multi_child().
* `owns` is true for commands created through init factories (the box
* deletes the command when the count reaches zero) and false for
* references into library-owned structures (multi children, stack
* entries): releasing those only destroys the box.
*/
struct OakUndoCommand {
struct OakUndoCommandBox {
olive::UndoCommand *command;
bool owned;
bool owns;
std::atomic<uint32_t> refs;
OakUndoCommandBox(olive::UndoCommand *c, bool o)
: command(c)
, owns(o)
, refs(1)
{
}
};
namespace oakundo_capi
{
inline OakUndoCommand make_command_handle(olive::UndoCommand *command,
bool owns);
inline void command_addref(void *ctx)
{
if (ctx) {
static_cast<OakUndoCommandBox *>(ctx)->refs.fetch_add(1);
}
}
inline void command_release(void *ctx)
{
if (!ctx) {
return;
}
OakUndoCommandBox *box = static_cast<OakUndoCommandBox *>(ctx);
if (box->refs.fetch_sub(1) == 1) {
if (box->owns) {
delete box->command;
}
delete box;
}
}
inline OakUndoCommand make_command_handle(olive::UndoCommand *command,
bool owns)
{
OakUndoCommand handle = {};
if (!command) {
return handle;
}
OakUndoCommandBox *box = new (std::nothrow) OakUndoCommandBox(command,
owns);
if (!box) {
if (owns) {
delete command;
}
return handle;
}
handle.ctx = box;
handle.addref = command_addref;
handle.release = command_release;
handle.abi_version = OAKUNDO_ABI_VERSION;
return handle;
}
inline olive::UndoCommand *to_command(OakUndoCommand h)
{
if (!h.ctx) {
return nullptr;
}
return static_cast<OakUndoCommandBox *>(h.ctx)->command;
}
inline void mark_container_owned(OakUndoCommand h)
{
if (h.ctx) {
static_cast<OakUndoCommandBox *>(h.ctx)->owns = false;
}
}
} // namespace oakundo_capi
#endif // OAK_UNDO_COMMANDHANDLE_H
+61 -66
View File
@@ -20,10 +20,17 @@
#include "undo/undocommand.h"
#include <atomic>
#include <new>
#include "../src/undocommand.h"
#include "commandhandle.h"
using oakundo_capi::make_command_handle;
using oakundo_capi::mark_container_owned;
using oakundo_capi::to_command;
namespace
{
@@ -33,7 +40,8 @@ namespace
class CallbackUndoCommand : public olive::UndoCommand {
public:
CallbackUndoCommand(const OakUndoCommandVtable &vtable, void *userdata)
: vtable_(vtable), userdata_(userdata)
: vtable_(vtable)
, userdata_(userdata)
{
}
@@ -64,75 +72,66 @@ private:
void *userdata_;
};
}
} // namespace
OakUndoCommand *oakundo_command_init(const OakUndoCommandVtable *vtable,
void *userdata)
OakUndoCommand oakundo_command_init(const OakUndoCommandVtable *vtable,
void *userdata)
{
if (!vtable) {
return NULL;
return OakUndoCommand{};
}
try {
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand();
if (!handle) {
return NULL;
}
handle->command = new CallbackUndoCommand(*vtable, userdata);
handle->owned = true;
return handle;
return make_command_handle(new CallbackUndoCommand(*vtable, userdata), true);
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
OakUndoCommand *oakundo_command_init_multi(void)
OakUndoCommand oakundo_command_init_multi(void)
{
try {
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand();
if (!handle) {
return NULL;
}
handle->command = new olive::MultiUndoCommand();
handle->owned = true;
return handle;
return make_command_handle(new olive::MultiUndoCommand(), true);
} catch (...) {
return NULL;
return OakUndoCommand{};
}
}
int oakundo_command_multi_add_child(OakUndoCommand *multi,
OakUndoCommand *child)
int oakundo_command_multi_add_child(OakUndoCommand multi,
OakUndoCommand child)
{
if (!multi || !multi->command || !child || !child->command) {
olive::UndoCommand *parent = to_command(multi);
olive::UndoCommand *child_cmd = to_command(child);
if (!parent || !child_cmd) {
return OAKUNDO_E_INVALID;
}
olive::MultiUndoCommand *mcu =
dynamic_cast<olive::MultiUndoCommand *>(multi->command);
dynamic_cast<olive::MultiUndoCommand *>(parent);
if (!mcu) {
return OAKUNDO_E_INVALID;
}
try {
mcu->add_child(child->command);
// Ownership of the underlying command moved to the multi command;
// consume the wrapper.
delete child;
mcu->add_child(child_cmd);
// The multi command now owns the C++ object; the caller's box
// becomes a non-owning reference (its release no longer deletes).
mark_container_owned(child);
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_command_multi_child_count(OakUndoCommand *multi, int *out_count)
int oakundo_command_multi_child_count(OakUndoCommand multi, int *out_count)
{
if (!multi || !multi->command || !out_count) {
olive::UndoCommand *parent = to_command(multi);
if (!parent || !out_count) {
return OAKUNDO_E_INVALID;
}
olive::MultiUndoCommand *mcu =
dynamic_cast<olive::MultiUndoCommand *>(multi->command);
dynamic_cast<olive::MultiUndoCommand *>(parent);
if (!mcu) {
return OAKUNDO_E_INVALID;
}
@@ -145,15 +144,16 @@ int oakundo_command_multi_child_count(OakUndoCommand *multi, int *out_count)
}
}
int oakundo_command_multi_child(OakUndoCommand *multi, int index,
OakUndoCommand **out_child)
int oakundo_command_multi_child(OakUndoCommand multi, int index,
OakUndoCommand *out_child)
{
if (!multi || !multi->command || !out_child) {
olive::UndoCommand *parent = to_command(multi);
if (!parent || !out_child) {
return OAKUNDO_E_INVALID;
}
olive::MultiUndoCommand *mcu =
dynamic_cast<olive::MultiUndoCommand *>(multi->command);
dynamic_cast<olive::MultiUndoCommand *>(parent);
if (!mcu) {
return OAKUNDO_E_INVALID;
}
@@ -163,41 +163,38 @@ int oakundo_command_multi_child(OakUndoCommand *multi, int index,
return OAKUNDO_E_NOT_FOUND;
}
OakUndoCommand *handle = new (std::nothrow) OakUndoCommand();
if (!handle) {
return OAKUNDO_E_NOMEM;
}
handle->command = mcu->child(index);
handle->owned = false;
*out_child = handle;
// Non-owning reference; the child stays owned by the multi command
*out_child = make_command_handle(mcu->child(index), false);
return out_child->ctx ? OAKUNDO_OK : OAKUNDO_E_NOMEM;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_command_redo_now(OakUndoCommand command)
{
olive::UndoCommand *c = to_command(command);
if (!c) {
return OAKUNDO_E_INVALID;
}
try {
c->redo_now();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_command_redo_now(OakUndoCommand *command)
int oakundo_command_undo_now(OakUndoCommand command)
{
if (!command || !command->command) {
olive::UndoCommand *c = to_command(command);
if (!c) {
return OAKUNDO_E_INVALID;
}
try {
command->command->redo_now();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_command_undo_now(OakUndoCommand *command)
{
if (!command || !command->command) {
return OAKUNDO_E_INVALID;
}
try {
command->command->undo_now();
c->undo_now();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
@@ -206,12 +203,10 @@ int oakundo_command_undo_now(OakUndoCommand *command)
void oakundo_command_free(OakUndoCommand *command)
{
if (!command) {
if (!command || !command->ctx) {
return;
}
if (command->owned) {
delete command->command;
}
delete command;
command->release(command->ctx);
command->ctx = NULL;
}
+118 -52
View File
@@ -20,192 +20,257 @@
#include "undo/undostack.h"
#include <atomic>
#include <cstring>
#include <new>
#include "../src/undostack.h"
#include "commandhandle.h"
struct OakUndoStack {
using oakundo_capi::mark_container_owned;
using oakundo_capi::to_command;
namespace
{
struct StackBox {
olive::UndoStack impl;
std::atomic<uint32_t> refs;
StackBox()
: refs(1)
{
}
};
OakUndoStack *oakundo_undostack_init(void)
void stack_addref(void *ctx)
{
try {
return new (std::nothrow) OakUndoStack();
} catch (...) {
return NULL;
if (ctx) {
static_cast<StackBox *>(ctx)->refs.fetch_add(1);
}
}
void stack_release(void *ctx)
{
if (!ctx) {
return;
}
StackBox *box = static_cast<StackBox *>(ctx);
if (box->refs.fetch_sub(1) == 1) {
delete box;
}
}
olive::UndoStack *to_stack(OakUndoStack h)
{
if (!h.ctx) {
return nullptr;
}
return &static_cast<StackBox *>(h.ctx)->impl;
}
} // namespace
OakUndoStack oakundo_undostack_init(void)
{
OakUndoStack handle = {};
StackBox *box = new (std::nothrow) StackBox();
if (!box) {
return handle;
}
handle.ctx = box;
handle.addref = stack_addref;
handle.release = stack_release;
handle.abi_version = OAKUNDO_ABI_VERSION;
return handle;
}
void oakundo_undostack_free(OakUndoStack *stack)
{
delete stack;
if (!stack || !stack->ctx) {
return;
}
stack->release(stack->ctx);
stack->ctx = NULL;
}
int oakundo_undostack_push(OakUndoStack *stack, OakUndoCommand *command,
int oakundo_undostack_push(OakUndoStack stack, OakUndoCommand command,
const char *name)
{
if (!stack || !command || !command->command) {
olive::UndoStack *s = to_stack(stack);
olive::UndoCommand *cmd = to_command(command);
if (!s || !cmd) {
return OAKUNDO_E_INVALID;
}
try {
olive::UndoCommand *impl = command->command;
stack->impl.push(impl, name ? name : "");
// Ownership of the underlying command moved to the stack (or was
// deleted as an empty multi command); consume the wrapper.
delete command;
s->push(cmd, name ? name : "");
// The stack now owns the C++ object (or deleted it as an empty
// multi command); the caller's box becomes a non-owning reference.
mark_container_owned(command);
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_push_pre_executed(OakUndoStack *stack,
OakUndoCommand *command,
int oakundo_undostack_push_pre_executed(OakUndoStack stack,
OakUndoCommand command,
const char *name)
{
if (!stack || !command || !command->command) {
olive::UndoStack *s = to_stack(stack);
olive::UndoCommand *cmd = to_command(command);
if (!s || !cmd) {
return OAKUNDO_E_INVALID;
}
try {
olive::UndoCommand *impl = command->command;
stack->impl.push_pre_executed(impl, name ? name : "");
delete command;
s->push_pre_executed(cmd, name ? name : "");
mark_container_owned(command);
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_undo(OakUndoStack *stack)
int oakundo_undostack_undo(OakUndoStack stack)
{
if (!stack) {
olive::UndoStack *s = to_stack(stack);
if (!s) {
return OAKUNDO_E_INVALID;
}
try {
stack->impl.undo();
s->undo();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_redo(OakUndoStack *stack)
int oakundo_undostack_redo(OakUndoStack stack)
{
if (!stack) {
olive::UndoStack *s = to_stack(stack);
if (!s) {
return OAKUNDO_E_INVALID;
}
try {
stack->impl.redo();
s->redo();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_jump(OakUndoStack *stack, int64_t index)
int oakundo_undostack_jump(OakUndoStack stack, int64_t index)
{
if (!stack) {
olive::UndoStack *s = to_stack(stack);
if (!s) {
return OAKUNDO_E_INVALID;
}
try {
stack->impl.jump(index < 0 ? 0 : static_cast<size_t>(index));
s->jump(index < 0 ? 0 : static_cast<size_t>(index));
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_clear(OakUndoStack *stack)
int oakundo_undostack_clear(OakUndoStack stack)
{
if (!stack) {
olive::UndoStack *s = to_stack(stack);
if (!s) {
return OAKUNDO_E_INVALID;
}
try {
stack->impl.clear();
s->clear();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_can_undo(OakUndoStack *stack, int *out_value)
int oakundo_undostack_can_undo(OakUndoStack stack, int *out_value)
{
if (!stack || !out_value) {
olive::UndoStack *s = to_stack(stack);
if (!s || !out_value) {
return OAKUNDO_E_INVALID;
}
try {
*out_value = stack->impl.can_undo() ? 1 : 0;
*out_value = s->can_undo() ? 1 : 0;
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_can_redo(OakUndoStack *stack, int *out_value)
int oakundo_undostack_can_redo(OakUndoStack stack, int *out_value)
{
if (!stack || !out_value) {
olive::UndoStack *s = to_stack(stack);
if (!s || !out_value) {
return OAKUNDO_E_INVALID;
}
try {
*out_value = stack->impl.can_redo() ? 1 : 0;
*out_value = s->can_redo() ? 1 : 0;
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_count(OakUndoStack *stack, int64_t *out_count)
int oakundo_undostack_count(OakUndoStack stack, int64_t *out_count)
{
if (!stack || !out_count) {
olive::UndoStack *s = to_stack(stack);
if (!s || !out_count) {
return OAKUNDO_E_INVALID;
}
try {
*out_count = stack->impl.command_count();
*out_count = s->command_count();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_index(OakUndoStack *stack, int64_t *out_index)
int oakundo_undostack_index(OakUndoStack stack, int64_t *out_index)
{
if (!stack || !out_index) {
olive::UndoStack *s = to_stack(stack);
if (!s || !out_index) {
return OAKUNDO_E_INVALID;
}
try {
*out_index = stack->impl.done_count();
*out_index = s->done_count();
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
}
}
int oakundo_undostack_command_text(OakUndoStack *stack, int64_t row,
int oakundo_undostack_command_text(OakUndoStack stack, int64_t row,
char *buf, int buf_size)
{
if (!stack) {
olive::UndoStack *s = to_stack(stack);
if (!s) {
return OAKUNDO_E_INVALID;
}
try {
if (row < 0 || row >= stack->impl.command_count()) {
if (row < 0 || row >= s->command_count()) {
return OAKUNDO_E_NOT_FOUND;
}
std::string name = stack->impl.command_name(int(row));
std::string name = s->command_name(int(row));
int required = static_cast<int>(name.size()) + 1;
if (buf && buf_size > 0) {
@@ -222,19 +287,20 @@ int oakundo_undostack_command_text(OakUndoStack *stack, int64_t row,
}
}
int oakundo_undostack_command_is_done(OakUndoStack *stack, int64_t row,
int oakundo_undostack_command_is_done(OakUndoStack stack, int64_t row,
int *out_value)
{
if (!stack || !out_value) {
olive::UndoStack *s = to_stack(stack);
if (!s || !out_value) {
return OAKUNDO_E_INVALID;
}
try {
if (row < 0 || row >= stack->impl.command_count()) {
if (row < 0 || row >= s->command_count()) {
return OAKUNDO_E_NOT_FOUND;
}
*out_value = stack->impl.command_is_done(int(row)) ? 1 : 0;
*out_value = s->command_is_done(int(row)) ? 1 : 0;
return OAKUNDO_OK;
} catch (...) {
return OAKUNDO_E_FAILED;
+34 -32
View File
@@ -46,11 +46,11 @@ OakUndoCommandVtable make_vtable()
return vtable;
}
OakUndoCommand *make_command(CommandLog &log)
OakUndoCommand make_command(CommandLog &log)
{
OakUndoCommandVtable vtable = make_vtable();
OakUndoCommand *command = oakundo_command_init(&vtable, &log);
EXPECT_NE(command, nullptr);
OakUndoCommand command = oakundo_command_init(&vtable, &log);
EXPECT_NE(command.ctx, nullptr);
return command;
}
@@ -59,25 +59,25 @@ OakUndoCommand *make_command(CommandLog &log)
TEST(OakUndoCommand, InitFree)
{
CommandLog log;
OakUndoCommand *command = make_command(log);
oakundo_command_free(command);
OakUndoCommand command = make_command(log);
oakundo_command_free(&command);
EXPECT_EQ(log.free_count, 1);
}
TEST(OakUndoCommand, InitNullVtableFails)
{
EXPECT_EQ(oakundo_command_init(nullptr, nullptr), nullptr);
EXPECT_EQ(oakundo_command_init(nullptr, nullptr).ctx, nullptr);
}
TEST(OakUndoCommand, FreeNullIsNoOp)
{
oakundo_command_free(nullptr);
{ OakUndoCommand h = {}; oakundo_command_free(&h); }
}
TEST(OakUndoCommand, RedoUndoNowRoundtrip)
{
CommandLog log;
OakUndoCommand *command = make_command(log);
OakUndoCommand command = make_command(log);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(log.redo_count, 1);
@@ -91,13 +91,15 @@ TEST(OakUndoCommand, RedoUndoNowRoundtrip)
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
EXPECT_EQ(log.undo_count, 1);
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(OakUndoCommand, RedoNowNullHandleFails)
{
EXPECT_EQ(oakundo_command_redo_now(nullptr), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_command_undo_now(nullptr), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_command_redo_now(OakUndoCommand{}),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_command_undo_now(OakUndoCommand{}),
OAKUNDO_E_INVALID);
}
TEST(OakUndoCommand, NullCallbacksAreNoOp)
@@ -107,19 +109,19 @@ TEST(OakUndoCommand, NullCallbacksAreNoOp)
vtable.undo = nullptr;
vtable.free_fn = nullptr;
OakUndoCommand *command = oakundo_command_init(&vtable, nullptr);
ASSERT_NE(command, nullptr);
OakUndoCommand command = oakundo_command_init(&vtable, nullptr);
ASSERT_NE(command.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(command), OAKUNDO_OK);
EXPECT_EQ(oakundo_command_undo_now(command), OAKUNDO_OK);
oakundo_command_free(command);
oakundo_command_free(&command);
}
TEST(OakUndoCommand, MultiAddChildAndCount)
{
CommandLog log_a;
CommandLog log_b;
OakUndoCommand *multi = oakundo_command_init_multi();
ASSERT_NE(multi, nullptr);
OakUndoCommand multi = oakundo_command_init_multi();
ASSERT_NE(multi.ctx, nullptr);
int count = -1;
EXPECT_EQ(oakundo_command_multi_child_count(multi, &count), OAKUNDO_OK);
@@ -142,7 +144,7 @@ TEST(OakUndoCommand, MultiAddChildAndCount)
EXPECT_EQ(log_b.undo_count, 1);
// Freeing the multi frees the children it owns.
oakundo_command_free(multi);
oakundo_command_free(&multi);
EXPECT_EQ(log_a.free_count, 1);
EXPECT_EQ(log_b.free_count, 1);
}
@@ -150,43 +152,43 @@ TEST(OakUndoCommand, MultiAddChildAndCount)
TEST(OakUndoCommand, MultiChildBorrowedHandle)
{
CommandLog log;
OakUndoCommand *multi = oakundo_command_init_multi();
ASSERT_NE(multi, nullptr);
OakUndoCommand multi = oakundo_command_init_multi();
ASSERT_NE(multi.ctx, nullptr);
ASSERT_EQ(oakundo_command_multi_add_child(multi, make_command(log)),
OAKUNDO_OK);
OakUndoCommand *child = nullptr;
OakUndoCommand child = {};
EXPECT_EQ(oakundo_command_multi_child(multi, 0, &child), OAKUNDO_OK);
ASSERT_NE(child, nullptr);
ASSERT_NE(child.ctx, nullptr);
EXPECT_EQ(oakundo_command_redo_now(child), OAKUNDO_OK);
EXPECT_EQ(log.redo_count, 1);
// Freeing the borrowed wrapper must not free the underlying command.
oakundo_command_free(child);
oakundo_command_free(&child);
EXPECT_EQ(log.free_count, 0);
oakundo_command_free(multi);
oakundo_command_free(&multi);
EXPECT_EQ(log.free_count, 1);
}
TEST(OakUndoCommand, MultiErrorPaths)
{
CommandLog log;
OakUndoCommand *multi = oakundo_command_init_multi();
ASSERT_NE(multi, nullptr);
OakUndoCommand *plain = make_command(log);
OakUndoCommand multi = oakundo_command_init_multi();
ASSERT_NE(multi.ctx, nullptr);
OakUndoCommand plain = make_command(log);
int count = 0;
OakUndoCommand *child = nullptr;
OakUndoCommand child = {};
EXPECT_EQ(oakundo_command_multi_add_child(nullptr, plain),
EXPECT_EQ(oakundo_command_multi_add_child(OakUndoCommand{}, plain),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_command_multi_add_child(multi, nullptr),
EXPECT_EQ(oakundo_command_multi_add_child(multi, OakUndoCommand{}),
OAKUNDO_E_INVALID);
// plain is not a multi command
EXPECT_EQ(oakundo_command_multi_add_child(plain, make_command(log)),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_command_multi_child_count(nullptr, &count),
EXPECT_EQ(oakundo_command_multi_child_count(OakUndoCommand{}, &count),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_command_multi_child_count(multi, nullptr),
OAKUNDO_E_INVALID);
@@ -197,6 +199,6 @@ TEST(OakUndoCommand, MultiErrorPaths)
EXPECT_EQ(oakundo_command_multi_child(multi, -1, &child),
OAKUNDO_E_NOT_FOUND);
oakundo_command_free(multi);
oakundo_command_free(plain);
oakundo_command_free(&multi);
oakundo_command_free(&plain);
}
+58 -58
View File
@@ -53,36 +53,36 @@ OakUndoCommandVtable make_vtable()
return vtable;
}
OakUndoCommand *make_command(CommandLog &log)
OakUndoCommand make_command(CommandLog &log)
{
OakUndoCommandVtable vtable = make_vtable();
OakUndoCommand *command = oakundo_command_init(&vtable, &log);
EXPECT_NE(command, nullptr);
OakUndoCommand command = oakundo_command_init(&vtable, &log);
EXPECT_NE(command.ctx, nullptr);
return command;
}
int64_t stack_index(OakUndoStack *stack)
int64_t stack_index(OakUndoStack stack)
{
int64_t index = -1;
EXPECT_EQ(oakundo_undostack_index(stack, &index), OAKUNDO_OK);
return index;
}
int64_t stack_count(OakUndoStack *stack)
int64_t stack_count(OakUndoStack stack)
{
int64_t count = -1;
EXPECT_EQ(oakundo_undostack_count(stack, &count), OAKUNDO_OK);
return count;
}
int stack_can_undo(OakUndoStack *stack)
int stack_can_undo(OakUndoStack stack)
{
int value = -1;
EXPECT_EQ(oakundo_undostack_can_undo(stack, &value), OAKUNDO_OK);
return value;
}
int stack_can_redo(OakUndoStack *stack)
int stack_can_redo(OakUndoStack stack)
{
int value = -1;
EXPECT_EQ(oakundo_undostack_can_redo(stack, &value), OAKUNDO_OK);
@@ -93,8 +93,8 @@ int stack_can_redo(OakUndoStack *stack)
TEST(OakUndoStack, InitFree)
{
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
// A fresh stack holds the "New/Open Project" empty command.
EXPECT_EQ(stack_count(stack), 1);
@@ -102,12 +102,12 @@ TEST(OakUndoStack, InitFree)
EXPECT_EQ(stack_can_undo(stack), 0);
EXPECT_EQ(stack_can_redo(stack), 0);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, FreeNullIsNoOp)
{
oakundo_undostack_free(nullptr);
{ OakUndoStack h = {}; oakundo_undostack_free(&h); }
}
TEST(OakUndoStack, NullHandleFails)
@@ -117,39 +117,39 @@ TEST(OakUndoStack, NullHandleFails)
int value = 0;
char buf[8];
EXPECT_EQ(oakundo_undostack_push(nullptr, make_command(log), "x"),
EXPECT_EQ(oakundo_undostack_push(OakUndoStack{}, make_command(log), "x"),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_push_pre_executed(nullptr, make_command(log),
EXPECT_EQ(oakundo_undostack_push_pre_executed(OakUndoStack{}, make_command(log),
"x"),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_undo(nullptr), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_redo(nullptr), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_jump(nullptr, 0), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_clear(nullptr), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_can_undo(nullptr, &value), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_can_redo(nullptr, &value), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_count(nullptr, &value64), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_index(nullptr, &value64), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_command_text(nullptr, 0, buf, sizeof(buf)),
EXPECT_EQ(oakundo_undostack_undo(OakUndoStack{}), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_redo(OakUndoStack{}), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_jump(OakUndoStack{}, 0), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_clear(OakUndoStack{}), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_can_undo(OakUndoStack{}, &value), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_can_redo(OakUndoStack{}, &value), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_count(OakUndoStack{}, &value64), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_index(OakUndoStack{}, &value64), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_command_text(OakUndoStack{}, 0, buf, sizeof(buf)),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_command_is_done(nullptr, 0, &value),
EXPECT_EQ(oakundo_undostack_command_is_done(OakUndoStack{}, 0, &value),
OAKUNDO_E_INVALID);
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
EXPECT_EQ(oakundo_undostack_push(stack, nullptr, "x"), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_push_pre_executed(stack, nullptr, "x"),
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
EXPECT_EQ(oakundo_undostack_push(stack, OakUndoCommand{}, "x"), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_push_pre_executed(stack, OakUndoCommand{}, "x"),
OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_can_undo(stack, nullptr), OAKUNDO_E_INVALID);
EXPECT_EQ(oakundo_undostack_count(stack, nullptr), OAKUNDO_E_INVALID);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, PushUndoRedoRoundtrip)
{
CommandLog log;
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push(stack, make_command(log), "edit"),
OAKUNDO_OK);
@@ -171,7 +171,7 @@ TEST(OakUndoStack, PushUndoRedoRoundtrip)
EXPECT_EQ(stack_can_undo(stack), 1);
EXPECT_EQ(stack_can_redo(stack), 0);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
EXPECT_EQ(log.free_count, 1);
}
@@ -179,8 +179,8 @@ TEST(OakUndoStack, PushClearsRedoable)
{
CommandLog log_a;
CommandLog log_b;
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push(stack, make_command(log_a), "a"),
OAKUNDO_OK);
@@ -194,14 +194,14 @@ TEST(OakUndoStack, PushClearsRedoable)
EXPECT_EQ(stack_can_redo(stack), 0);
EXPECT_EQ(stack_count(stack), 2);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, PushPreExecutedSkipsRedo)
{
CommandLog log;
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push_pre_executed(stack, make_command(log),
"done elsewhere"),
@@ -215,33 +215,33 @@ TEST(OakUndoStack, PushPreExecutedSkipsRedo)
ASSERT_EQ(oakundo_undostack_redo(stack), OAKUNDO_OK);
EXPECT_EQ(log.redo_count, 1);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, EmptyMultiIsDiscarded)
{
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
OakUndoCommand *multi = oakundo_command_init_multi();
ASSERT_NE(multi, nullptr);
OakUndoCommand multi = oakundo_command_init_multi();
ASSERT_NE(multi.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push(stack, multi, "empty"), OAKUNDO_OK);
EXPECT_EQ(stack_count(stack), 1);
multi = oakundo_command_init_multi();
ASSERT_NE(multi, nullptr);
ASSERT_NE(multi.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push_pre_executed(stack, multi, "empty"),
OAKUNDO_OK);
EXPECT_EQ(stack_count(stack), 1);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, Jump)
{
CommandLog logs[3];
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
for (int i = 0; i < 3; i++) {
char name[8];
@@ -271,14 +271,14 @@ TEST(OakUndoStack, Jump)
ASSERT_EQ(oakundo_undostack_jump(stack, -5), OAKUNDO_OK);
EXPECT_EQ(stack_index(stack), 1);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, Clear)
{
CommandLog log;
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push(stack, make_command(log), "edit"),
OAKUNDO_OK);
@@ -294,14 +294,14 @@ TEST(OakUndoStack, Clear)
int(strlen("New/Open Project")) + 1);
EXPECT_STREQ(buf, "New/Open Project");
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, CommandTextTwoStage)
{
CommandLog log;
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push(stack, make_command(log), "hello"),
OAKUNDO_OK);
@@ -333,14 +333,14 @@ TEST(OakUndoStack, CommandTextTwoStage)
OAKUNDO_OK);
EXPECT_EQ(oakundo_undostack_command_text(stack, 2, nullptr, 0), 1);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, CommandIsDone)
{
CommandLog log;
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
ASSERT_EQ(oakundo_undostack_push(stack, make_command(log), "edit"),
OAKUNDO_OK);
@@ -359,13 +359,13 @@ TEST(OakUndoStack, CommandIsDone)
EXPECT_EQ(oakundo_undostack_command_is_done(stack, 0, nullptr),
OAKUNDO_E_INVALID);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
TEST(OakUndoStack, MaxUndoCommands)
{
OakUndoStack *stack = oakundo_undostack_init();
ASSERT_NE(stack, nullptr);
OakUndoStack stack = oakundo_undostack_init();
ASSERT_NE(stack.ctx, nullptr);
// The fresh stack holds 1 empty command; push well past the 200 cap.
std::vector<std::unique_ptr<CommandLog>> logs;
@@ -397,7 +397,7 @@ TEST(OakUndoStack, MaxUndoCommands)
EXPECT_EQ(stack_can_undo(stack), 0);
EXPECT_EQ(stack_count(stack), 200);
oakundo_undostack_free(stack);
oakundo_undostack_free(&stack);
}
namespace