1
0
Fork 0
forked from hanez/xtc
xtc/src/project/history.c

119 lines
3 KiB
C
Raw Normal View History

#include "../graph/graph_internal.h"
#include "project_internal.h"
#include <stdlib.h>
#include <string.h>
2026-10-27 01:37:21 +01:00
struct xtc_history {
xtc_project *states[XTC_HISTORY_EDITS + 1];
size_t count, cursor;
uint64_t next_track, next_clip, next_note;
size_t next_node;
};
2026-10-27 01:37:21 +01:00
static void remember_ids(xtc_history *h, const xtc_project *p)
{
if (p->next_track_id > h->next_track)
h->next_track = p->next_track_id;
if (p->next_clip_id > h->next_clip)
h->next_clip = p->next_clip_id;
if (p->next_note_id > h->next_note)
h->next_note = p->next_note_id;
if (p->graph->next_id > h->next_node)
h->next_node = p->graph->next_id;
}
2026-10-27 01:37:21 +01:00
void xtc_history_destroy(xtc_history *h)
{
size_t i;
if (!h)
return;
for (i = 0; i < h->count; ++i)
xtc_project_destroy(h->states[i]);
free(h);
}
2026-10-27 01:37:21 +01:00
xtc_result xtc_history_create(const xtc_project *p, xtc_history **out)
{
xtc_history *h;
xtc_result r;
if (!out)
return XTC_ERR_INVALID_ARGUMENT;
*out = NULL;
if (!p)
return XTC_ERR_INVALID_ARGUMENT;
h = calloc(1, sizeof(*h));
if (!h)
return XTC_ERR_OUT_OF_MEMORY;
r = xtc_project_clone(p, h->states);
if (r != XTC_OK) {
free(h);
return r;
}
remember_ids(h, p);
h->count = 1;
*out = h;
return XTC_OK;
}
2026-10-27 01:37:21 +01:00
xtc_result xtc_history_record(xtc_history *h, const xtc_project *p)
{
xtc_project *copy;
size_t i;
xtc_result r;
if (!h || !p)
return XTC_ERR_INVALID_ARGUMENT;
r = xtc_project_clone(p, &copy);
if (r != XTC_OK)
return r;
remember_ids(h, p);
for (i = h->cursor + 1; i < h->count; ++i)
xtc_project_destroy(h->states[i]);
h->count = h->cursor + 1;
if (h->count == XTC_HISTORY_EDITS + 1) {
xtc_project_destroy(h->states[0]);
memmove(h->states, h->states + 1, XTC_HISTORY_EDITS * sizeof(*h->states));
--h->count;
}
h->states[h->count++] = copy;
h->cursor = h->count - 1;
return XTC_OK;
}
2026-10-27 01:37:21 +01:00
static int available(const xtc_history *h, int redo)
{
return redo ? h->cursor + 1 < h->count : h->cursor > 0;
}
2026-10-27 01:37:21 +01:00
xtc_result xtc_history_checkout(const xtc_history *h, int redo, xtc_project **out)
{
if (!out)
return XTC_ERR_INVALID_ARGUMENT;
*out = NULL;
if (!h || (redo != 0 && redo != 1))
return XTC_ERR_INVALID_ARGUMENT;
if (!available(h, redo))
return XTC_ERR_NOT_FOUND;
{
xtc_result r = xtc_project_clone(h->states[redo ? h->cursor + 1 : h->cursor - 1], out);
if (r == XTC_OK) {
(*out)->next_track_id = h->next_track;
(*out)->next_clip_id = h->next_clip;
(*out)->next_note_id = h->next_note;
(*out)->graph->next_id = h->next_node;
}
return r;
}
}
2026-10-27 01:37:21 +01:00
xtc_result xtc_history_accept(xtc_history *h, int redo)
{
if (!h || (redo != 0 && redo != 1))
return XTC_ERR_INVALID_ARGUMENT;
if (!available(h, redo))
return XTC_ERR_NOT_FOUND;
if (redo)
++h->cursor;
else
--h->cursor;
return XTC_OK;
}