summaryrefslogtreecommitdiff
path: root/src/editor/properties.cpp
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-07-28 19:11:34 +0200
committeraura <nw@moneybot.cc>2026-07-28 19:11:34 +0200
commit86d248ed2b033fe36ce53b0387b2cbdcb69c0b72 (patch)
treea70f32a0f44b927a6d137998efa405e330689c0f /src/editor/properties.cpp
parent468813b133a6a3ff0b85d3b34f1009cfeae815e4 (diff)
finish undo/redo
Diffstat (limited to 'src/editor/properties.cpp')
-rw-r--r--src/editor/properties.cpp127
1 files changed, 76 insertions, 51 deletions
diff --git a/src/editor/properties.cpp b/src/editor/properties.cpp
index 109e622..dc2233d 100644
--- a/src/editor/properties.cpp
+++ b/src/editor/properties.cpp
@@ -112,7 +112,6 @@ U8 gui_editor_propview_is_selected( GUI_EDITOR_PROPVIEW *e, void *what, U8 selty
void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
void* valuep = eprop_ptr( prop );
- EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
for( auto& it : view->curselect ) {
EOBJECT* eobj = (EOBJECT*)it.obj;
EDITOR_PROP* otherp = eprop_from_name( eobj, prop->displayname );
@@ -121,26 +120,19 @@ void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( otherp && otherp->type == prop->type ) {
void* targetp = eprop_ptr( otherp );
if( targetp != valuep ) {
- EDITOR_UNDO_PROPS::CHANGES changes;
void* oldval = alloca( prop->size );
memcpy( oldval, targetp, prop->size );
memcpy( targetp, valuep, prop->size );
-
- changes.props.push( { prop->hash, prop->size, oldval, targetp } );
- changes.obj = eobj;
- rec.props.changes.push( changes );
}
}
}
-
- if( rec.props.changes.size )
- editor->undo_actions.push( rec );
}
void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, const char* propname ) {
if( view->curselect.size < 2 ) return;
- EDITOR_PROP** pptr = view->curprops.where( fn( EDITOR_PROP** pptr ) { return (*pptr)->displayname == propname; } );
+ FNV1A hash = fnv1a( propname );
+ EDITOR_PROP** pptr = view->curprops.where( fn( EDITOR_PROP** pptr ) { return (*pptr)->hash == hash; } );
if( !pptr )
return;
@@ -151,7 +143,6 @@ void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( !fdiff )
return;
- EDITOR_UNDO_ACTION rec{ .type = EDITOR_UNDO_EDITPROPS };
for( auto& it : view->curselect ) {
EOBJECT* eobj = (EOBJECT*)it.obj;
EDITOR_PROP* otherp = eprop_from_name( eobj, prop->displayname );
@@ -162,21 +153,10 @@ void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( targetp == eprop_ptr( prop ) )
continue;
- EDITOR_UNDO_PROPS::CHANGES changes;
- F32* oldval = (F32*)alloca( prop->size );
- memcpy( oldval, targetp, prop->size );
-
for( U32 i = 0; i < valc; ++i )
targetp[i] += fdiff[i];
-
- changes.props.push( { prop->hash, prop->size, oldval, targetp } );
- changes.obj = eobj;
- rec.props.changes.push( changes );
}
}
-
- if( rec.props.changes.size )
- editor->undo_actions.push( rec );
}
void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, const char* propname, F32* fdiff, U32 valc ) {
@@ -188,6 +168,54 @@ void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, const char
gui_editor_propview_sync_props_fdiff( view, *pptr, fdiff, valc );
}
+void gui_editor_propview_undo_eprop_start( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
+ view->pending_undo.typemask |= EDITOR_UNDO_EDITPROPS;
+ for( auto& it : view->curselect ) {
+ EDITOR_PROP* tprop = eprop_from_hash( (EOBJECT*)it.obj, prop->hash );
+ if( !tprop ) continue;
+
+ EDITOR_UNDO_PROPS* undo_props = &view->pending_undo.props;
+ EDITOR_UNDO_PROPS::CHANGES* change = undo_props->changes.where( fn( EDITOR_UNDO_PROPS::CHANGES* v ) {
+ return v->obj == (EOBJECT*)it.obj;
+ } );
+
+ if( !change ) {
+ change = undo_props->changes.push( { .obj = (EOBJECT*)it.obj } );
+ }
+
+ EDITOR_UNDO_PROPS::PROP_VALUE* propv = change->props.where( fn( EDITOR_UNDO_PROPS::PROP_VALUE* v ) {
+ return v->hash == prop->hash;
+ } );
+
+ if( propv ) {
+ continue;
+ }
+
+ propv = change->props.push( { tprop->hash, tprop->size } );
+ memcpy( propv->oldval.data, eprop_ptr( tprop ), tprop->size );
+ }
+}
+
+void gui_editor_propview_undo_mapprop( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
+ view->pending_undo.typemask |= EDITOR_UNDO_CREATE_MAPPROP;
+ view->pending_undo.mapprop.ref = *(MAP_PROPREF*)eprop_ptr( prop );
+}
+
+void gui_editor_propview_undo_commit( GUI_EDITOR_PROPVIEW* view ) {
+ for( auto& it : view->pending_undo.props.changes ) {
+ EOBJECT* obj = it.obj;
+ for( auto& it2 : it.props ) {
+ EDITOR_PROP* tprop = eprop_from_hash( obj, it2.hash );
+ if( !tprop ) continue;
+
+ memcpy( it2.newval.data, eprop_ptr( tprop ), tprop->size );
+ }
+ }
+
+ editor_push_undo_action( editor, view->pending_undo );
+ view->pending_undo = {};
+}
+
// todo : int diff
struct TEXBTN_CB {
@@ -211,26 +239,22 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
switch( prop->type ) {
case EPROP_F32: { GUI_FLOATINPUT* in = gui_floatinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), min, max, step );
in->drawval = val;
- in->cb = pfn( void* ptr ) {
- GUI_FLOATINPUT* fin = (GUI_FLOATINPUT*)ptr;
- gui_editor_propview_sync_props_fdiff( editor->gui.props, (EDITOR_PROP*)fin->cbextra, &fin->lastchange, 1 );
- }; in->cbextra = prop;
+ in->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ in->cb = cfn( void* ) { gui_editor_propview_sync_props_fdiff( editor->gui.props, prop, &in->lastchange, 1 ); };
+ in->release_cb = cfn( void* ) { gui_editor_propview_undo_commit( editor->gui.props ); };
*y += (s+18);
} break;
case EPROP_VEC2: case EPROP_VEC3: case EPROP_VEC4: { U32 c = prop->type - EPROP_VEC2 + 2;
GUI_VECTORINPUT* in = gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), c, min, max, step, "xyzw", c == 2 ? "%.03f" : "%0.02f", val );
- in->cb = pfn( void* ptr ) {
- GUI_VECTORINPUT* vin = (GUI_VECTORINPUT*)ptr;
- gui_editor_propview_sync_props_fdiff( editor->gui.props, (EDITOR_PROP*)vin->cbextra, vin->lastchange.data, vin->inputs.size );
- }; in->cbextra = prop;
-
+ in->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ in->cb = cfn( void* ) { gui_editor_propview_sync_props_fdiff( editor->gui.props, prop, in->lastchange.data, in->inputs.size ); };
+ in->release_cb = cfn( void* ) { gui_editor_propview_undo_commit( editor->gui.props ); };
*y += (s+18);
} break;
- case EPROP_CLR: { GUI_COLORINPUT* cin = gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) );
- cin->cb = pfn( void* ptr ) {
- GUI_COLORINPUT* cin = (GUI_COLORINPUT*)ptr;
- gui_editor_propview_sync_props_fdiff( editor->gui.props, (EDITOR_PROP*)cin->cbextra, cin->lastchange.data, cin->inputs.size );
- }; cin->cbextra = prop;
+ case EPROP_CLR: { GUI_COLORINPUT* in = gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) );
+ in->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ in->cb = cfn( void* ) { gui_editor_propview_sync_props_fdiff( editor->gui.props, prop, in->lastchange.data, in->inputs.size ); };
+ in->release_cb = cfn( void* ) { gui_editor_propview_undo_commit( editor->gui.props ); };
*y += (s+18);
}break;
case EPROP_MAPPROP: {
@@ -239,18 +263,19 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( val ) gui_label( *x, *y, "prop id: %d", *ref );
else gui_label( *x, *y, "prop id: *" );
- GUI_BUTTON* newprop = gui_button( action2_x, *y, 20, 20, "+", pfn( void* ptr ) {
- GUI_BUTTON* btn = (GUI_BUTTON*)ptr;
+ gui_button( action2_x, *y, 20, 20, "+", cfn( void* ) {
SURF_PROPS props{ .tex = 0, .clr = CLR::WHITE() };
editor->map->props.push( props );
- EDITOR_PROP* eprop = (EDITOR_PROP*)btn->extra;
- MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( eprop );
+ MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( prop );
+ gui_editor_propview_undo_eprop_start( view, prop );
(ref)->id = editor->map->props.size - 1;
editor->gui.assets_scroll = ( editor->map->props.size + 1 ) * 28;
- gui_editor_propview_sync_props_value( editor->gui.props, eprop );
+ gui_editor_propview_undo_mapprop( view, prop );
+ gui_editor_propview_sync_props_value( editor->gui.props, prop );
+ gui_editor_propview_undo_commit( view );
gui_editor_propview_update( editor->gui.props );
- } ); newprop->extra = prop;
+ } );
if( val ) {
GUI_BUTTON* goprop = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) {
@@ -265,16 +290,15 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
if( val && *tex ) gui_label( *x, *y, "%s: %s", n, (*tex)->name );
else if( !val ) gui_label( *x, *y, "%s: *", n );
else gui_label( *x, *y, "%s: none", n );
- GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", cfn( void* ptr ) {
- GUI_BUTTON* btn = (GUI_BUTTON*)ptr;
- GL_TEX2D** ptex = (GL_TEX2D**)btn->extra;
- GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, ptex );
- picker->cb = pfn( void* p ) {
- GUI_EDITOR_TEXTUREPICKER* picker = (GUI_EDITOR_TEXTUREPICKER*)p;
- gui_editor_propview_sync_props_value( editor->gui.props, (EDITOR_PROP*)picker->cbextra );
+ gui_button( action_x, *y, 20, 20, "\x1A", cfn( void* ptr ) {
+ GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, tex );
+ picker->pre_cb = cfn( void* ) { gui_editor_propview_undo_eprop_start( view, prop ); };
+ picker->cb = cfn( void* p ) {
+ gui_editor_propview_sync_props_value( editor->gui.props, prop );
+ gui_editor_propview_undo_commit( view );
gui_editor_propview_update( editor->gui.props );
- }; picker->cbextra = prop;
- } ); btn->extra = tex; *y += s;
+ };
+ } ); *y += s;
} break;
case EPROP_VERTEX_LIST: {
LIST<MAP_VERTEX>* list = ( LIST<MAP_VERTEX>* )eprop_ptr( prop );
@@ -612,6 +636,7 @@ GUI_EDITOR_PROPVIEW* gui_editor_propview( I32 x, I32 y, I32 w, I32 h ) {
view->input_fn = gui_base_input_fn;
view->curselect = {};
+ view->pending_undo = {};
GUI_VIEW* parent = gui_get_view();
parent->children.push( view );