summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/editor/editor.cpp62
-rw-r--r--src/editor/editor.h12
-rw-r--r--src/editor/editor_infobox.cpp14
-rw-r--r--src/editor/properties.cpp221
-rw-r--r--src/editor/properties.h54
-rw-r--r--src/editor/view2d.cpp138
-rw-r--r--src/game/physics/movement.cpp2
-rw-r--r--src/gui/base.h5
-rw-r--r--src/gui/floatinput.cpp12
-rw-r--r--src/gui/vectorinput.cpp12
-rw-r--r--src/util/string.h48
-rw-r--r--src/util/typedef.h4
12 files changed, 412 insertions, 172 deletions
diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp
index ba61961..c96f908 100644
--- a/src/editor/editor.cpp
+++ b/src/editor/editor.cpp
@@ -31,7 +31,7 @@ void editor_clear_gui_state_refs( GAME_EDITOR* e ) {
e->gui.header_viewtype = 0;
}
-static void editor_push_undo_action( GAME_EDITOR* e, const GAME_EDITOR::EDITOR_UNDO_ACTION& action ) {
+void editor_push_undo_action( GAME_EDITOR* e, const GAME_EDITOR::EDITOR_UNDO_ACTION& action ) {
if( !e )
return;
@@ -39,7 +39,7 @@ static void editor_push_undo_action( GAME_EDITOR* e, const GAME_EDITOR::EDITOR_U
e->undo_actions.push( action );
}
-static void editor_refresh_after_map_change( GAME_EDITOR* e ) {
+void editor_refresh_after_map_change( GAME_EDITOR* e ) {
if( !e || !e->map )
return;
@@ -54,13 +54,13 @@ static U8 editor_clr_eq( const CLR& a, const CLR& b ) {
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
-static U8 editor_vertex_eq( const MAP_VERTEX& a, const MAP_VERTEX& b ) {
+U8 editor_vertex_eq( const MAP_VERTEX& a, const MAP_VERTEX& b ) {
return a.pos == b.pos
&& a.uv == b.uv
&& editor_clr_eq( a.clr, b.clr );
}
-static U8 editor_wall_eq( const MAP_WALL& a, const MAP_WALL& b ) {
+U8 editor_wall_eq( const MAP_WALL& a, const MAP_WALL& b ) {
return a.start == b.start
&& a.end == b.end
&& a.uvstart == b.uvstart
@@ -68,7 +68,7 @@ static U8 editor_wall_eq( const MAP_WALL& a, const MAP_WALL& b ) {
&& a.propid == b.propid;
}
-static U8 editor_poly_eq( const MAP_POLYGON& a, const MAP_POLYGON& b ) {
+U8 editor_poly_eq( const MAP_POLYGON& a, const MAP_POLYGON& b ) {
if( a.type != b.type || a.propid != b.propid )
return 0;
if( !( a.mins == b.mins ) || !( a.maxs == b.maxs ) )
@@ -83,19 +83,19 @@ static U8 editor_poly_eq( const MAP_POLYGON& a, const MAP_POLYGON& b ) {
return 1;
}
-static U8 editor_sprite_eq( const MAP_SPRITE& a, const MAP_SPRITE& b ) {
+U8 editor_sprite_eq( const MAP_SPRITE& a, const MAP_SPRITE& b ) {
return a.pos == b.pos
&& a.size == b.size
&& editor_clr_eq( a.clr, b.clr )
&& a.tex == b.tex;
}
-static U8 editor_entity_eq( const MAP_ENTITY& a, const MAP_ENTITY& b ) {
+U8 editor_entity_eq( const MAP_ENTITY& a, const MAP_ENTITY& b ) {
return a.pos == b.pos
&& a.classid == b.classid;
}
-static I32 editor_clamp_valid_idx( I32 idx, I32 size ) {
+I32 editor_clamp_valid_idx( I32 idx, I32 size ) {
if( size <= 0 )
return -1;
if( idx < 0 )
@@ -105,12 +105,12 @@ static I32 editor_clamp_valid_idx( I32 idx, I32 size ) {
return idx;
}
-static I32 editor_idx_distance( I32 a, I32 b ) {
+I32 editor_idx_distance( I32 a, I32 b ) {
return a > b ? a - b : b - a;
}
template <typename MATCH_FN>
-static I32 editor_find_nearest_idx( I32 size, I32 expected_idx, MATCH_FN match ) {
+I32 editor_find_nearest_idx( I32 size, I32 expected_idx, MATCH_FN match ) {
if( size <= 0 )
return -1;
@@ -134,7 +134,7 @@ static I32 editor_find_nearest_idx( I32 size, I32 expected_idx, MATCH_FN match )
return best;
}
-static I32 editor_find_wall_idx( WORLD_MAP* map, const MAP_WALL& want, I32 expected_idx ) {
+I32 editor_find_wall_idx( WORLD_MAP* map, const MAP_WALL& want, I32 expected_idx ) {
if( !map )
return -1;
@@ -143,7 +143,7 @@ static I32 editor_find_wall_idx( WORLD_MAP* map, const MAP_WALL& want, I32 expec
} );
}
-static I32 editor_find_poly_idx( WORLD_MAP* map, const MAP_POLYGON& want, I32 expected_idx ) {
+I32 editor_find_poly_idx( WORLD_MAP* map, const MAP_POLYGON& want, I32 expected_idx ) {
if( !map )
return -1;
@@ -152,7 +152,7 @@ static I32 editor_find_poly_idx( WORLD_MAP* map, const MAP_POLYGON& want, I32 ex
} );
}
-static I32 editor_find_sprite_idx( WORLD_MAP* map, const MAP_SPRITE& want, I32 expected_idx ) {
+I32 editor_find_sprite_idx( WORLD_MAP* map, const MAP_SPRITE& want, I32 expected_idx ) {
if( !map )
return -1;
@@ -161,7 +161,7 @@ static I32 editor_find_sprite_idx( WORLD_MAP* map, const MAP_SPRITE& want, I32 e
} );
}
-static I32 editor_find_entity_idx( WORLD_MAP* map, const MAP_ENTITY& want, I32 expected_idx ) {
+I32 editor_find_entity_idx( WORLD_MAP* map, const MAP_ENTITY& want, I32 expected_idx ) {
if( !map )
return -1;
@@ -170,14 +170,9 @@ static I32 editor_find_entity_idx( WORLD_MAP* map, const MAP_ENTITY& want, I32 e
} );
}
-static void editor_mark_clear_wall_refs( GAME_EDITOR* e, MAP_WALL* w, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
- if( e->gui.props ) {
- if( e->gui.props->seltype == EDITOR_SELECT_WALL && e->gui.props->curselect == w )
- *clear_props_select = 1;
- if( e->gui.props->seltype == EDITOR_SELECT_WVERTEX
- && ( e->gui.props->curselect == &w->start || e->gui.props->curselect == &w->end ) )
- *clear_props_select = 1;
- }
+void editor_mark_clear_wall_refs( GAME_EDITOR* e, MAP_WALL* w, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
+ if( gui_editor_propview_is_selected( e->gui.props, w, EDITOR_SELECT_WALL ) )
+ *clear_props_select = 1;
if( e->gui.v2d ) {
if( e->gui.v2d->seltype == EDITOR_SELECT_WALL && e->gui.v2d->curselect == w )
@@ -194,16 +189,12 @@ static void editor_mark_clear_wall_refs( GAME_EDITOR* e, MAP_WALL* w, U8* clear_
}
}
-static void editor_mark_clear_poly_refs( GAME_EDITOR* e, MAP_POLYGON* p, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
- if( e->gui.props ) {
- if( e->gui.props->seltype == EDITOR_SELECT_POLY && e->gui.props->curselect == p )
+void editor_mark_clear_poly_refs( GAME_EDITOR* e, MAP_POLYGON* p, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
+ if( gui_editor_propview_is_selected( e->gui.props, p, EDITOR_SELECT_POLY ) )
+ *clear_props_select = 1;
+ for( auto& it : p->vertices ) {
+ if( gui_editor_propview_is_selected( e->gui.props, &it, EDITOR_SELECT_PVERTEX ) )
*clear_props_select = 1;
- if( e->gui.props->seltype == EDITOR_SELECT_PVERTEX ) {
- p->vertices.each( fn( MAP_VERTEX* v ) {
- if( e->gui.props->curselect == v )
- *clear_props_select = 1;
- } );
- }
}
if( e->gui.v2d ) {
@@ -227,8 +218,9 @@ static void editor_mark_clear_poly_refs( GAME_EDITOR* e, MAP_POLYGON* p, U8* cle
}
}
-static void editor_mark_clear_sprite_refs( GAME_EDITOR* e, MAP_SPRITE* s, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
- if( e->gui.props && e->gui.props->seltype == EDITOR_SELECT_SPRITE && e->gui.props->curselect == s )
+void editor_mark_clear_sprite_refs( GAME_EDITOR* e, MAP_SPRITE* s, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
+ // todo : only clear the selected item
+ if( gui_editor_propview_is_selected( e->gui.props, s, EDITOR_SELECT_SPRITE ) )
*clear_props_select = 1;
if( e->gui.v2d ) {
@@ -239,8 +231,8 @@ static void editor_mark_clear_sprite_refs( GAME_EDITOR* e, MAP_SPRITE* s, U8* cl
}
}
-static void editor_mark_clear_entity_refs( GAME_EDITOR* e, MAP_ENTITY* ent, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
- if( e->gui.props && e->gui.props->seltype == EDITOR_SELECT_ENT && e->gui.props->curselect == ent )
+void editor_mark_clear_entity_refs( GAME_EDITOR* e, MAP_ENTITY* ent, U8* clear_props_select, U8* clear_view_select, U8* clear_view_drag ) {
+ if( gui_editor_propview_is_selected( e->gui.props, ent, EDITOR_SELECT_ENT ) )
*clear_props_select = 1;
if( e->gui.v2d ) {
diff --git a/src/editor/editor.h b/src/editor/editor.h
index 33396df..4050029 100644
--- a/src/editor/editor.h
+++ b/src/editor/editor.h
@@ -264,9 +264,13 @@ struct GUI_EDITOR_2DVIEW : GUI_VIEW {
};
struct GUI_EDITOR_PROPVIEW : GUI_VIEW {
- void* curselect;
- U8 seltype;
+ struct PROPVIEW_SELECT {
+ void* obj;
+ U8 seltype;
+ };
+ LIST<PROPVIEW_SELECT> curselect;
+ LIST<EDITOR_PROP*> curprops;
GUI_VIEW* itemview;
};
@@ -299,6 +303,7 @@ struct GUI_EDITOR_TEXTUREPICKER : GUI_WINDOW {
GUI_LABEL* densitylabel;
GUI_CALLBACK cb;
+ void* cbextra;
};
@@ -330,7 +335,8 @@ extern GUI_EDITORWINDOW* gui_editorwindow( I32 w, I32 h );
extern GUI_EDITOR_2DVIEW* gui_editor_2dview( I32 x, I32 y, I32 w, I32 h );
extern GUI_EDITOR_3DVIEW* gui_editor_3dview( I32 x, I32 y, I32 w, I32 h );
extern GUI_EDITOR_PROPVIEW* gui_editor_propview( I32 x, I32 y, I32 w, I32 h );
-extern void gui_editor_propview_select( GUI_EDITOR_PROPVIEW* e, void* what, U8 seltype );
+extern void gui_editor_propview_select( GUI_EDITOR_PROPVIEW* e, void* what, U8 seltype, U8 clearall = 1 );
+extern U8 gui_editor_propview_is_selected( GUI_EDITOR_PROPVIEW* e, void* what, U8 seltype );
extern void gui_editor_propview_update( GUI_EDITOR_PROPVIEW* e );
extern GUI_EDITOR_TOOLVIEW* gui_editor_toolview( I32 x, I32 y, I32 w, I32 h );
extern void gui_editor_toolview_update( GUI_EDITOR_TOOLVIEW* view );
diff --git a/src/editor/editor_infobox.cpp b/src/editor/editor_infobox.cpp
index 479b59d..173e849 100644
--- a/src/editor/editor_infobox.cpp
+++ b/src/editor/editor_infobox.cpp
@@ -70,12 +70,14 @@ static void gui_editor_infobox_draw_assets( GUI_EDITOR_INFOBOX* box, I32 panel_x
SURF_PROPS* p = map_entry ? 0 : &map->props[idx - 1];
U8 selected = 0;
if( editor->gui.props ) {
- if( map_entry ) {
- selected = editor->gui.props->seltype == EDITOR_SELECT_ORIGIN
- && editor->gui.props->curselect == editor->map;
- } else {
- selected = editor->gui.props->seltype == EDITOR_SELECT_SURFPROPS
- && editor->gui.props->curselect == p;
+ if( editor->gui.props->curselect.size == 1 ) {
+ if( map_entry ) {
+ selected = editor->gui.props->curselect.data->seltype == EDITOR_SELECT_ORIGIN
+ && editor->gui.props->curselect.data->obj == editor->map;
+ } else {
+ selected = editor->gui.props->curselect.data->seltype == EDITOR_SELECT_SURFPROPS
+ && editor->gui.props->curselect.data->obj == p;
+ }
}
}
diff --git a/src/editor/properties.cpp b/src/editor/properties.cpp
index c9eb991..0cc0e56 100644
--- a/src/editor/properties.cpp
+++ b/src/editor/properties.cpp
@@ -45,30 +45,106 @@ I32 propview_action2_x( GUI_EDITOR_PROPVIEW* view ) {
);
}
-void gui_editor_propview_select( GUI_EDITOR_PROPVIEW* view, void* what, U8 seltype ) {
+void gui_editor_propview_select( GUI_EDITOR_PROPVIEW* view, void* what, U8 seltype, U8 clearall ) {
+ using PROPSELECT = GUI_EDITOR_PROPVIEW::PROPVIEW_SELECT;
if( !editor->map )
return;
+ view->curprops.clear();
+ if( clearall )
+ view->curselect.clear();
+
+ PROPSELECT sel{
+ .obj = what,
+ .seltype = seltype
+ };
+
if( seltype == EDITOR_SELECT_WVERTEX ) {
MAP_WALL* s = editor->map->walls.where( fn( MAP_WALL* s ) {
return ( &s->start == what || &s->end == what );
} );
if( !s )
- return gui_editor_propview_select( view, editor->map, EDITOR_SELECT_ORIGIN );
+ return gui_editor_propview_select( view, editor->map, EDITOR_SELECT_ORIGIN, 1 );
- view->curselect = s;
- view->seltype = EDITOR_SELECT_WALL;
- return gui_editor_propview_update( view );
+ sel.obj = s;
+ sel.seltype = EDITOR_SELECT_WALL;
}
- view->curselect = what;
- view->seltype = seltype;
+ if( view->curselect.idx_where( fn( PROPSELECT* p ) { return p->obj == sel.obj; } ) != -1 )
+ return;
+
+ view->curselect.push( sel );
gui_editor_propview_update( view );
}
+U8 gui_editor_propview_is_selected( GUI_EDITOR_PROPVIEW *e, void *what, U8 seltype ) {
+ for( auto& it : e->curselect ) {
+ if( it.obj == what && it.seltype == seltype )
+ return 1;
+ }
+ return 0;
+}
+
+void gui_editor_propview_sync_props_value( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop ) {
+ void* valuep = eprop_ptr( prop );
+ for( auto& it : view->curselect ) {
+ EOBJECT* eobj = (EOBJECT*)it.obj;
+ EDITOR_PROP* otherp = eprop_from_name( eobj, prop->displayname );
+ if( otherp == prop ) continue;
+
+ if( otherp && otherp->type == prop->type ) {
+ void* targetp = eprop_ptr( otherp );
+ if( targetp != valuep )
+ memcpy( targetp, valuep, prop->size );
+ }
+ }
+}
+
+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; } );
+ if( !pptr )
+ return;
+ gui_editor_propview_sync_props_value( view, *pptr );
+}
+
+void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, F32* fdiff, U32 valc ) {
+ for( auto& it : view->curselect ) {
+ EOBJECT* eobj = (EOBJECT*)it.obj;
+ EDITOR_PROP* otherp = eprop_from_name( eobj, prop->displayname );
+ if( otherp == prop ) continue;
+
+ if( otherp && otherp->type == prop->type ) {
+ F32* targetp = (F32*)eprop_ptr( otherp );
+ if( targetp == eprop_ptr( prop ) )
+ continue;
+
+ for( U32 i = 0; i < valc; ++i )
+ targetp[i] += fdiff[i];
+ }
+ }
+}
+
+void gui_editor_propview_sync_props_fdiff( GUI_EDITOR_PROPVIEW* view, const char* propname, F32* fdiff, U32 valc ) {
+ if( view->curselect.size < 2 ) return;
+ EDITOR_PROP** pptr = view->curprops.where( fn( EDITOR_PROP** pptr ) { return (*pptr)->displayname == propname; } );
+ if( !pptr )
+ return;
+
+ gui_editor_propview_sync_props_fdiff( view, *pptr, fdiff, valc );
+}
+
+// todo : int diff
+
+struct TEXBTN_CB {
+ EDITOR_PROP* prop;
+ GL_TEX2D** texp;
+};
+
+void gui_editor_propview_create_eobj_prop_ro( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, I32* x, I32* y, I32 w, I32 space );
void gui_editor_propview_create_eobj_props( GUI_EDITOR_PROPVIEW* view, EOBJECT* e, I32* x, I32* y, I32 w );
void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, I32* x, I32* y, I32 w, I32 space ) {
F32 action_x = propview_action_x( view );
@@ -82,11 +158,29 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
else step = editor->propgrid ? editor->grid : 0.25f;
switch( prop->type ) {
- case EPROP_F32: gui_floatinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), min, max, step ); *y += (space+18); break;
- case EPROP_VEC2: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 2, min, max, step, "xy", "%.03f" ); *y += (space+18); break;
- case EPROP_VEC3: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 3, min, max, step, "xyz", "%.02f" ); *y += (space+18); break;
- case EPROP_VEC4: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 3, min, max, step, "xyzw", "%0.02f" ); *y += (space+18); break;
- case EPROP_CLR: gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) ); *y += (space+18); break;
+ case EPROP_F32: { GUI_FLOATINPUT* in = gui_floatinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), min, max, step );
+ 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;
+ *y += (space+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" );
+ 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;
+
+ *y += (space+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;
+ *y += (space+18);
+ }break;
case EPROP_MAPPROP: {
MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( prop );
SURF_PROPS* props = map_get_props( editor->map, *ref );
@@ -96,11 +190,14 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
GUI_BUTTON* btn = (GUI_BUTTON*)ptr;
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*)btn->extra)->id = editor->map->props.size - 1;
+ (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_update( editor->gui.props );
- } ); newprop->extra = ref;
+ } ); newprop->extra = prop;
GUI_BUTTON* goprop = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) {
GUI_BUTTON* btn = (GUI_BUTTON*)ptr;
@@ -113,11 +210,15 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
GL_TEX2D** tex = (GL_TEX2D**)eprop_ptr( prop );
if( *tex ) gui_label( *x, *y, "%s: %s", n, (*tex)->name );
else gui_label( *x, *y, "%s: none", n );
- GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) {
+ 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* ) { gui_editor_propview_update( editor->gui.props ); };
+ 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_editor_propview_update( editor->gui.props );
+ }; picker->cbextra = prop;
} ); btn->extra = tex; *y += space;
} break;
case EPROP_VERTEX_LIST: {
@@ -132,7 +233,7 @@ void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PRO
} ); btn->extra = v; *y += space;
}
} break;
- default: break;
+ default: return gui_editor_propview_create_eobj_prop_ro( view, prop, x, y, w, space ); break;
}
}
@@ -152,6 +253,7 @@ void gui_editor_propview_create_eobj_prop_ro( GUI_EDITOR_PROPVIEW* view, EDITOR_
case EPROP_I32: str += to_str( *(I32*)ptr ); break;
case EPROP_I64: str += to_str( *(I64*)ptr ); break;
case EPROP_STRING: str += to_str( *(CLR*)ptr ); break;
+ default: str += STR("UNIMPL_TYPE : ") + to_str( prop->type ); return;
}
str += "]";
@@ -172,7 +274,7 @@ void gui_editor_propview_create_eobj_props( GUI_EDITOR_PROPVIEW* view, EOBJECT*
}
void gui_editor_propview_create_wallprops( GUI_EDITOR_PROPVIEW* view ) {
- MAP_WALL* s = (MAP_WALL*)view->curselect;
+ MAP_WALL* s = (MAP_WALL*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
I32 x = 10, y = 10;
@@ -187,7 +289,7 @@ void gui_editor_propview_create_wallprops( GUI_EDITOR_PROPVIEW* view ) {
}
void gui_editor_propview_create_polyprops( GUI_EDITOR_PROPVIEW* view ) {
- MAP_POLYGON* p = (MAP_POLYGON*)view->curselect;
+ MAP_POLYGON* p = (MAP_POLYGON*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
I32 x = 10, y = 10;
I32 space = 20;
@@ -201,7 +303,7 @@ void gui_editor_propview_create_polyprops( GUI_EDITOR_PROPVIEW* view ) {
}
void gui_editor_propview_create_mapprops( GUI_EDITOR_PROPVIEW* view ) {
- WORLD_MAP* m = (WORLD_MAP*)view->curselect;
+ WORLD_MAP* m = (WORLD_MAP*)view->curselect.data[0].obj;
I32 x = 10, y = 10;
I32 space = 20;
@@ -236,7 +338,7 @@ void gui_editor_propview_create_mapprops( GUI_EDITOR_PROPVIEW* view ) {
}
void gui_editor_propview_create_pvertexprops( GUI_EDITOR_PROPVIEW* view ) {
- MAP_VERTEX* v = (MAP_VERTEX*)view->curselect;
+ MAP_VERTEX* v = (MAP_VERTEX*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
I32 x = 10, y = 10;
@@ -254,7 +356,7 @@ void gui_editor_propview_create_pvertexprops( GUI_EDITOR_PROPVIEW* view ) {
gui_label( x, y, "polygon idx: %d", poly_idx );
gui_button( action_x, y - 2, 20, 20, "\x1A", pfn( void* ) {
GUI_EDITOR_PROPVIEW* view = editor->gui.props;
- MAP_VERTEX* v = (MAP_VERTEX*)view->curselect;
+ MAP_VERTEX* v = (MAP_VERTEX*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
MAP_POLYGON* polygon = m->polygons.where( fn( MAP_POLYGON* p ) {
I32 vert_idx = p->vertices.idx_where( fn( MAP_VERTEX* pv ) { return (pv == v); } );
@@ -270,7 +372,7 @@ void gui_editor_propview_create_pvertexprops( GUI_EDITOR_PROPVIEW* view ) {
void gui_editor_propview_create_spriteprops( GUI_EDITOR_PROPVIEW* view ) {
- MAP_SPRITE* s = (MAP_SPRITE*)view->curselect;
+ MAP_SPRITE* s = (MAP_SPRITE*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
I32 x = 10, y = 10;
@@ -285,7 +387,7 @@ void gui_editor_propview_create_spriteprops( GUI_EDITOR_PROPVIEW* view ) {
}
void gui_editor_propview_create_surfprops( GUI_EDITOR_PROPVIEW* view ) {
- SURF_PROPS* p = (SURF_PROPS*)view->curselect;
+ SURF_PROPS* p = (SURF_PROPS*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
I32 x = 10, y = 10;
@@ -300,7 +402,7 @@ void gui_editor_propview_create_surfprops( GUI_EDITOR_PROPVIEW* view ) {
}
void gui_editor_propview_create_entprops( GUI_EDITOR_PROPVIEW* view ) {
- MAP_ENTITY* e = (MAP_ENTITY*)view->curselect;
+ MAP_ENTITY* e = (MAP_ENTITY*)view->curselect.data[0].obj;
WORLD_MAP* m = editor->map;
I32 x = 10, y = 10;
@@ -317,6 +419,41 @@ void gui_editor_propview_create_entprops( GUI_EDITOR_PROPVIEW* view ) {
gui_vectorinput( x, y, propview_input_width( view ), "position", (F32*)&e->pos, 3, -INFINITY, INFINITY, step ); y += (space+18);
}
+void gui_editor_propview_filter_props( GUI_EDITOR_PROPVIEW* view ) {
+ if( view->curselect.size < 2 ) return view->curprops.clear();
+
+ EOBJECT* first = (EOBJECT*)view->curselect.data[0].obj;
+ for( auto& it : first->eprops ) {
+ U8 add = 1;
+ EDITOR_PROP* prop = eprop_from_ref( first, it );
+ for( U32 i = 1; i < view->curselect.size; ++i ) {
+ EOBJECT* obj = (EOBJECT*)view->curselect.data[i].obj;
+ if( !eprop_from_name( obj, prop->displayname ) ) {
+ add = 0;
+ break;
+ }
+ }
+
+ if( add )
+ view->curprops.push( prop );
+ }
+}
+
+void gui_editor_propview_create_groupprops( GUI_EDITOR_PROPVIEW* view ) {
+ if( !view->curprops.size )
+ gui_editor_propview_filter_props( view );
+
+ I32 x = 10, y = 10, w = propview_input_width( view );
+ U32 space = 20;
+
+ for( auto& it : view->curprops ) {
+ if( it->readonly )
+ gui_editor_propview_create_eobj_prop_ro( view, it, &x, &y, w, space );
+ else
+ gui_editor_propview_create_eobj_prop( view, it, &x, &y, w, space );
+ }
+}
+
void gui_editor_propview_update( GUI_EDITOR_PROPVIEW* view ) {
if( !editor->map ) return;
@@ -327,20 +464,31 @@ void gui_editor_propview_update( GUI_EDITOR_PROPVIEW* view ) {
gui_set_view( view->itemview );
view->itemview->initheld = 1;
- switch( view->seltype ) {
- case EDITOR_SELECT_WALL: gui_editor_propview_create_wallprops( view ); break;
- case EDITOR_SELECT_POLY: gui_editor_propview_create_polyprops( view ); break;
- case EDITOR_SELECT_ORIGIN: gui_editor_propview_create_mapprops( view ); break;
- case EDITOR_SELECT_ENT: gui_editor_propview_create_entprops( view ); break;
- case EDITOR_SELECT_PVERTEX: gui_editor_propview_create_pvertexprops( view ); break;
- case EDITOR_SELECT_SPRITE: gui_editor_propview_create_spriteprops( view ); break;
- case EDITOR_SELECT_SURFPROPS: gui_editor_propview_create_surfprops( view ); break;
- default: break;
+ if( !view->curselect.size )
+ return;
+
+ if( view->curselect.size > 1 ) {
+ gui_editor_propview_create_groupprops( view );
+ } else {
+ switch( view->curselect.data->seltype ) {
+ case EDITOR_SELECT_WALL: gui_editor_propview_create_wallprops( view ); break;
+ case EDITOR_SELECT_POLY: gui_editor_propview_create_polyprops( view ); break;
+ case EDITOR_SELECT_ORIGIN: gui_editor_propview_create_mapprops( view ); break;
+ case EDITOR_SELECT_ENT: gui_editor_propview_create_entprops( view ); break;
+ case EDITOR_SELECT_PVERTEX: gui_editor_propview_create_pvertexprops( view ); break;
+ case EDITOR_SELECT_SPRITE: gui_editor_propview_create_spriteprops( view ); break;
+ case EDITOR_SELECT_SURFPROPS: gui_editor_propview_create_surfprops( view ); break;
+ default: break;
+ }
}
}
void gui_editor_propview_get_title( GUI_EDITOR_PROPVIEW* view, char* buf ) {
- switch( view->seltype ) {
+ if( view->curselect.size > 1 ) {
+ sprintf( buf, "group properties" ); return;
+ }
+
+ switch( view->curselect.data->seltype ) {
case EDITOR_SELECT_NONE: sprintf( buf, "properties" ); break;
case EDITOR_SELECT_POLY: sprintf( buf, "polygon properties" ); break;
case EDITOR_SELECT_ORIGIN: sprintf( buf, "properties" ); break;
@@ -389,8 +537,7 @@ GUI_EDITOR_PROPVIEW* gui_editor_propview( I32 x, I32 y, I32 w, I32 h ) {
view->draw_fn = gui_editor_propview_draw_fn;
view->input_fn = gui_base_input_fn;
- view->curselect = 0;
- view->seltype = 0;
+ view->curselect = {};
GUI_VIEW* parent = gui_get_view();
parent->children.push( view );
diff --git a/src/editor/properties.h b/src/editor/properties.h
index d663a6b..ef59b0d 100644
--- a/src/editor/properties.h
+++ b/src/editor/properties.h
@@ -5,14 +5,15 @@
#if IS_EDITOR
#include <math.h>
#include "../util/string.h"
+#include "../util/fnv.h"
#define EPROP( _type, name, value, display ) \
_type name = value; \
- EDITOR_PROP name##_prop{ &name, eprop_type<_type>(), display, this, 0 }
+ EDITOR_PROP name##_prop{ &name, eprop_type<_type>(), display, this, sizeof(_type), 0 }
#define EPROP_RO( _type, name, value, display ) \
_type name = value; \
- EDITOR_PROP name##_prop{ &name, eprop_type<_type>(), display, this, 1 }
+ EDITOR_PROP name##_prop{ &name, eprop_type<_type>(), display, this, sizeof(_type), 1 }
#define EPROP_RANGED( _type, name, value, display, _min, _max ) \
_type name = value; \
@@ -23,6 +24,7 @@
this, \
_min, \
_max, \
+ sizeof(_type), \
0 \
}
@@ -34,6 +36,7 @@
display, \
step, \
this, \
+ sizeof(_type), \
0 \
}
@@ -47,6 +50,7 @@
this, \
min, \
max, \
+ sizeof(_type), \
0 \
}
@@ -90,13 +94,15 @@ concept __eobject_base = __is_base_of(EOBJECT, T);
// editor object property
struct EDITOR_PROP {
- EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, struct EOBJECT* _parent, U8 _readonly = 0 ) {
+ EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, struct EOBJECT* _parent, U32 _size, U8 _readonly = 0 ) {
type = _type;
displayname = _displayname;
min = -INFINITY;
max = INFINITY;
step = 0;
readonly = _readonly;
+ hash = fnv1a( _displayname );
+ size = _size;
U64 _this = (U64)this;
U64 pdata = (U64)_pdata;
@@ -109,13 +115,15 @@ struct EDITOR_PROP {
dataoff = offset;
}
- EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, F32 _step, struct EOBJECT* _parent, U8 _readonly = 0 ) {
+ EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, F32 _step, struct EOBJECT* _parent, U32 _size, U8 _readonly = 0 ) {
type = _type;
displayname = _displayname;
min = -INFINITY;
max = INFINITY;
step = _step;
readonly = _readonly;
+ hash = fnv1a( _displayname );
+ size = _size;
U64 _this = (U64)this;
U64 pdata = (U64)_pdata;
@@ -128,13 +136,15 @@ struct EDITOR_PROP {
dataoff = offset;
}
- EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, struct EOBJECT* _parent, F32 _min, F32 _max, U8 _readonly = 0 ) {
+ EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, struct EOBJECT* _parent, F32 _min, F32 _max, U32 _size, U8 _readonly = 0 ) {
type = _type;
displayname = _displayname;
min = _min;
max = _max;
step = 0;
readonly = _readonly;
+ hash = fnv1a( _displayname );
+ size = _size;
U64 _this = (U64)this;
U64 pdata = (U64)_pdata;
@@ -147,13 +157,15 @@ struct EDITOR_PROP {
dataoff = offset;
}
- EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, F32 _step, struct EOBJECT* _parent, F32 _min, F32 _max, U8 _readonly = 0 ) {
+ EDITOR_PROP( void* _pdata, U8 _type, STR _displayname, F32 _step, struct EOBJECT* _parent, F32 _min, F32 _max, U32 _size, U8 _readonly = 0 ) {
type = _type;
displayname = _displayname;
min = _min;
max = _max;
step = _step;
readonly = _readonly;
+ hash = fnv1a( _displayname );
+ size = _size;
U64 _this = (U64)this;
U64 pdata = (U64)_pdata;
@@ -173,6 +185,8 @@ struct EDITOR_PROP {
F64 max{ INFINITY };
F32 step;
U8 readonly;
+ FNV1A hash;
+ U32 size;
template <typename T> struct __eprop_type {
static const U8 type = EPROP_INVALID;
@@ -209,6 +223,18 @@ inline void* eprop_ptr( EDITOR_PROP* prop ) {
return (void*)( (U64)prop - prop->dataoff);
}
+inline EDITOR_PROP* eprop_from_name( EOBJECT* obj, STR name ) {
+ FNV1A fnv = fnv1a( name );
+
+ for( auto& it : obj->eprops ) {
+ EDITOR_PROP* prop = eprop_from_ref( obj, it );
+ if( fnv == prop->hash )
+ return prop;
+ }
+
+ return 0;
+}
+
template <typename T>
const U8 eprop_type() {
return EDITOR_PROP::__eprop_type<T>::type;
@@ -216,6 +242,18 @@ const U8 eprop_type() {
#else
struct EOBJECT {};
-#define EPROP( type, name, value, displayname ) \
- type name{ value };
+#define EPROP( _type, name, value, display ) \
+ _type name = value;
+
+#define EPROP_RO( _type, name, value, display ) \
+ _type name = value;
+
+#define EPROP_RANGED( _type, name, value, display, _min, _max ) \
+ _type name = value;
+
+#define EPROP_STEP( _type, name, value, display, step ) \
+ _type name = value;
+
+#define EPROP_RANGED_STEP( _type, name, value, display, min, max, step ) \
+ _type name = value;
#endif
diff --git a/src/editor/view2d.cpp b/src/editor/view2d.cpp
index f1b5b17..8bcd588 100644
--- a/src/editor/view2d.cpp
+++ b/src/editor/view2d.cpp
@@ -1,4 +1,5 @@
#include <math.h>
+#include "SDL_scancode.h"
#include "editor.h"
#include "../render/gl_2d.h"
#include "../game/object.h"
@@ -187,13 +188,15 @@ void gui_editor_2dview_select( GUI_EDITOR_2DVIEW* view, void* what, U8 seltype )
U8 gui_editor_2dview_is_gizmo_active( GUI_EDITOR_2DVIEW* view, void* what, U8 seltype ) {
GUI_EDITOR_PROPVIEW* props = editor->gui.props;
- if( props->seltype == EDITOR_SELECT_WALL && (seltype == EDITOR_SELECT_WVERTEX) ) {
- MAP_WALL* s = (MAP_WALL*)props->curselect;
- if( what == &s->start || what == &s->end )
+ for( auto& it : props->curselect ) {
+ if( it.seltype == EDITOR_SELECT_WALL && (seltype == EDITOR_SELECT_WVERTEX) ) {
+ MAP_WALL* s = (MAP_WALL*)it.obj;
+ if( what == &s->start || what == &s->end )
+ return 1;
+ }
+ else if( it.seltype == seltype && it.obj == what ) {
return 1;
- }
- else if( props->seltype == seltype && props->curselect == what ) {
- return 1;
+ }
}
if( view->curdrag ) {
@@ -830,9 +833,11 @@ void gui_editor_2dview_input_select_onmove( GUI_EDITOR_2DVIEW* view ) {
GUI_EDITOR_PROPVIEW* props = editor->gui.props;
// special case for dragging wall vertices, just always update
- U8 iswallv = props->seltype == EDITOR_SELECT_WALL && view->dragtype == EDITOR_SELECT_WVERTEX;
- if( props->curselect == view->curdrag || iswallv )
- gui_editor_propview_update( editor->gui.props );
+ for( auto& it : props->curselect ) {
+ U8 iswallv = it.seltype == EDITOR_SELECT_WALL && view->dragtype == EDITOR_SELECT_WVERTEX;
+ if( it.obj == view->curdrag || iswallv )
+ gui_editor_propview_update( editor->gui.props );
+ }
}
void gui_editor_2dview_input_select_drag_wall( GUI_EDITOR_2DVIEW* view ) {
@@ -955,7 +960,7 @@ void gui_editor_2dview_input_select_drag_origin( GUI_EDITOR_2DVIEW* view ) {
void gui_editor_2dview_input_select_ondrop( GUI_EDITOR_2DVIEW* view ) {
if( !view->dragmoved )
- gui_editor_propview_select( editor->gui.props, view->curdrag, view->dragtype );
+ gui_editor_propview_select( editor->gui.props, view->curdrag, view->dragtype, !input.keys[SDL_SCANCODE_LCTRL] );
view->curdrag = 0;
}
@@ -1389,76 +1394,77 @@ void gui_editor_2dview_input_tool_draw( GUI_EDITOR_2DVIEW* view ) {
}
void gui_editor_view2d_delete_obj( GUI_EDITOR_2DVIEW* view ) {
- void* it;
- U8 type;
-
+ LIST<GUI_EDITOR_PROPVIEW::PROPVIEW_SELECT> sel{};
if( view->curdrag && view->dragtype ) {
- it = view->curdrag;
- type = view->dragtype;
+ sel.push( {
+ .obj = view->curdrag,
+ .seltype = view->dragtype
+ } );
view->curdrag = 0;
view->dragtype = EDITOR_SELECT_NONE;
- } else if( editor->gui.props->curselect ) {
- it = editor->gui.props->curselect;
- type = editor->gui.props->seltype;
+ } else if( editor->gui.props->curselect.size ) {
view->curselect = 0;
view->seltype = EDITOR_SELECT_NONE;
+ sel = editor->gui.props->curselect;
+ editor->gui.props->curselect.clear();
+
+ gui_editor_propview_select( editor->gui.props, 0, 0 );
}
else return;
- U8 cleared = 1;
- switch( type ) {
- case EDITOR_SELECT_POLY: {
- I32 idx = editor->map->polygons.idx_of( (MAP_POLYGON*)it );
- if( idx != -1 )
- editor->map->polygons.erase( idx );
- } break;
- case EDITOR_SELECT_WALL: {
- I32 idx = editor->map->walls.idx_of( (MAP_WALL*)it );
- if( idx != -1 )
- editor->map->walls.erase( idx );
- }; break;
- case EDITOR_SELECT_SPRITE: {
- I32 idx = editor->map->sprites.idx_of( (MAP_SPRITE*)it );
- if( idx != -1 )
- editor->map->sprites.erase( idx );
- }; break;
- case EDITOR_SELECT_ENT: {
- I32 idx = editor->map->entities.idx_of( (MAP_ENTITY*)it );
- if( idx != -1 )
- editor->map->entities.erase( idx );
- }; break;
- case EDITOR_SELECT_PVERTEX: {
- I32 vidx = -1, idx = editor->map->polygons.idx_where( fn( MAP_POLYGON* p ) {
- vidx = p->vertices.idx_where( fn( MAP_VERTEX* v ) {
- return v == it;
+ for( auto& _it: sel ) {
+ void* it = _it.obj;
+ U8 type = _it.seltype;
+ switch( type ) {
+ case EDITOR_SELECT_POLY: {
+ I32 idx = editor->map->polygons.idx_of( (MAP_POLYGON*)it );
+ if( idx != -1 )
+ editor->map->polygons.erase( idx );
+ } break;
+ case EDITOR_SELECT_WALL: {
+ I32 idx = editor->map->walls.idx_of( (MAP_WALL*)it );
+ if( idx != -1 )
+ editor->map->walls.erase( idx );
+ }; break;
+ case EDITOR_SELECT_SPRITE: {
+ I32 idx = editor->map->sprites.idx_of( (MAP_SPRITE*)it );
+ if( idx != -1 )
+ editor->map->sprites.erase( idx );
+ }; break;
+ case EDITOR_SELECT_ENT: {
+ I32 idx = editor->map->entities.idx_of( (MAP_ENTITY*)it );
+ if( idx != -1 )
+ editor->map->entities.erase( idx );
+ }; break;
+ case EDITOR_SELECT_PVERTEX: {
+ I32 vidx = -1, idx = editor->map->polygons.idx_where( fn( MAP_POLYGON* p ) {
+ vidx = p->vertices.idx_where( fn( MAP_VERTEX* v ) {
+ return v == it;
+ } );
+ return vidx != -1;
} );
- return vidx != -1;
- } );
- if( idx != -1 && vidx != -1 ) {
- MAP_POLYGON* p = &editor->map->polygons[idx];
- if( p->vertices.size <= 3 ) {
- editor->map->polygons.erase( idx );
- break;
+ if( idx != -1 && vidx != -1 ) {
+ MAP_POLYGON* p = &editor->map->polygons[idx];
+ if( p->vertices.size <= 3 ) {
+ editor->map->polygons.erase( idx );
+ break;
+ }
+ editor->map->polygons[idx].vertices.erase( vidx );
}
- editor->map->polygons[idx].vertices.erase( vidx );
- }
- }; break;
- case EDITOR_SELECT_WVERTEX: {
- I32 idx = editor->map->walls.idx_where( fn( MAP_WALL* w ) {
- return &w->end == it || &w->start == it;
- } );
+ }; break;
+ case EDITOR_SELECT_WVERTEX: {
+ I32 idx = editor->map->walls.idx_where( fn( MAP_WALL* w ) {
+ return &w->end == it || &w->start == it;
+ } );
- if( idx != -1 )
- editor->map->walls.erase( idx );
- }; break;
- default:
- cleared = 0; break;
+ if( idx != -1 )
+ editor->map->walls.erase( idx );
+ }; break;
+ default: break;
+ }
}
- if( cleared && it == editor->gui.props->curselect ) {
- gui_editor_propview_select( editor->gui.props, 0, 0 );
- }
}
void gui_editor_2dview_key_input( GUI_EDITOR_2DVIEW* view ) {
diff --git a/src/game/physics/movement.cpp b/src/game/physics/movement.cpp
index 094bc81..838c8a9 100644
--- a/src/game/physics/movement.cpp
+++ b/src/game/physics/movement.cpp
@@ -616,8 +616,6 @@ void gmove_full_walk_move() {
gmove_start_gravity();
// todo:
- // jump,
- // categorizepos
// more
if( gmove->input->jump )
diff --git a/src/gui/base.h b/src/gui/base.h
index 293de74..0418afd 100644
--- a/src/gui/base.h
+++ b/src/gui/base.h
@@ -229,6 +229,8 @@ struct GUI_FLOATINPUT : GUI_BASE {
F32 max;
F32 step;
+ F32 lastchange;
+
I32 lastmx;
U8 heldoutbounds;
U8 held;
@@ -239,6 +241,7 @@ struct GUI_FLOATINPUT : GUI_BASE {
U8 wraparound;
GUI_CALLBACK cb;
+ void* cbextra;
};
struct GUI_VECTORINPUT : GUI_VIEW {
@@ -253,8 +256,10 @@ struct GUI_VECTORINPUT : GUI_VIEW {
GUI_VIEW* inputview;
LIST<GUI_FLOATINPUT*> inputs;
+ LIST<F32> lastchange;
GUI_CALLBACK cb;
+ void* cbextra;
};
struct GUI_COLORINPUT : GUI_VECTORINPUT {};
diff --git a/src/gui/floatinput.cpp b/src/gui/floatinput.cpp
index 5746758..5ce92fe 100644
--- a/src/gui/floatinput.cpp
+++ b/src/gui/floatinput.cpp
@@ -166,6 +166,7 @@ void gui_floatinput_input_bound( GUI_FLOATINPUT* input ) {
if( !gui_mbutton_down( GUI_MBTNLEFT ) )
return;
+ F32 oldval = *input->pval;
I32 x = gui_relx( input );
I32 w = gui_floatinput_content_w( input );
@@ -182,6 +183,8 @@ void gui_floatinput_input_bound( GUI_FLOATINPUT* input ) {
F32 nval = min + (max - min) * progress;
F32 rmn = remainderf( nval, input->step );
*input->pval = nval - rmn;
+ if( oldval != *input->pval )
+ input->lastchange = *input->pval - oldval;
}
void gui_floatinput_input_unbound( GUI_FLOATINPUT* input ) {
@@ -191,6 +194,7 @@ void gui_floatinput_input_unbound( GUI_FLOATINPUT* input ) {
I32 mx, my;
gui_cursor_pos( &mx, &my );
+ F32 oldval = *input->pval;
I32 dx = mx - input->lastmx;
if( dx )
*input->pval += dx * input->step;
@@ -205,6 +209,8 @@ void gui_floatinput_input_unbound( GUI_FLOATINPUT* input ) {
F32 rmn = remainderf( *input->pval, input->step );
*input->pval -= rmn;
+ if( oldval != *input->pval )
+ input->lastchange = *input->pval - oldval;
}
void gui_floatinput_input_scroll( GUI_FLOATINPUT* input ) {
@@ -229,6 +235,7 @@ void gui_floatinput_input_scroll( GUI_FLOATINPUT* input ) {
F32 rmn = remainderf( nval, input->step );
*input->pval = nval - rmn;
+ input->lastchange = *input->pval - oldval;
if( input->cb )
input->cb( input );
}
@@ -261,13 +268,15 @@ void gui_floatinput_input_fn( void* ptr ) {
return;
}
- if( !input->held ) {
+ if( !input->held && !input->heldoutbounds ) {
U8 fine = !!m2;
I32 split_y = y + 1 + ( h - 2 ) / 2;
U8 inc = my < split_y;
F32 step = fine ? 0.1f : 1.f;
+ F32 val = *input->pval;
*input->pval += inc ? step : -step;
gui_floatinput_clamp_and_snap( input );
+ input->lastchange = *input->pval - val;
if( input->cb )
input->cb( input );
input->held = 1;
@@ -320,6 +329,7 @@ struct GUI_FLOATINPUT* gui_floatinput( I32 x, I32 y, I32 w, const char* title, F
input->input_fn = gui_floatinput_input_fn;
input->draw_fn = gui_floatinput_draw_fn;
+ input->lastchange = 0;
input->cb = 0;
input->pval = pval;
input->min = min;
diff --git a/src/gui/vectorinput.cpp b/src/gui/vectorinput.cpp
index 9ebb0fa..daed540 100644
--- a/src/gui/vectorinput.cpp
+++ b/src/gui/vectorinput.cpp
@@ -25,6 +25,16 @@ void gui_vectorinput_child_cb( void* ptr ) {
GUI_FLOATINPUT* child = (GUI_FLOATINPUT*)ptr;
// slider -> child view -> vectorinput
GUI_VECTORINPUT* parent = (GUI_VECTORINPUT*)child->parent->parent;
+ for( auto& it : parent->lastchange )
+ it = 0.f;
+
+ for( U32 i = 0; i < parent->inputs.size; ++i ) {
+ if( parent->inputs.data[i] == child ) {
+ parent->lastchange.data[i] = child->lastchange;
+ break;
+ }
+ }
+
if( parent->cb )
parent->cb( parent );
}
@@ -54,6 +64,7 @@ void __gui_internal_vectorinput_init(
GUI_VIEW* parent = gui_get_view();
parent->children.push( input );
input->parent = parent;
+ input->lastchange.resize( valc );
gui_set_view( input );
@@ -77,6 +88,7 @@ void __gui_internal_vectorinput_init(
printfmt
);
+ input->inputs.push( slider );
slider->cb = gui_vectorinput_child_cb;
}
diff --git a/src/util/string.h b/src/util/string.h
index 672fb5d..2725fd2 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -1,5 +1,6 @@
#pragma once
#include <cstdio>
+#include <wchar.h>
#include <stdarg.h>
#include <string.h>
@@ -65,12 +66,21 @@ struct __str : public LIST<CT> {
va_start( args, fmt );
va_list args2;
va_copy( args2, args );
- U32 c = vsnprintf( 0, 0, fmt, args );
- va_end( args );
- this->reserve( c * 2 );
- vsnprintf( this->data, c + 1, fmt, args2 );
- this->data[c] = 0;
- this->size = c;
+ if constexpr( sizeof( CT ) == 1 ) {
+ U32 c = vsnprintf( 0, 0, fmt, args );
+ va_end( args );
+ this->reserve( c * 2 );
+ vsnprintf( this->data, c + 1, fmt, args2 );
+ this->data[c] = 0;
+ this->size = c;
+ } else {
+ U32 c = vswprintf( 0, 0, fmt, args );
+ va_end( args );
+ this->reserve( c * 2 );
+ vswprintf( this->data, c + 1, fmt, args2 );
+ this->data[c] = 0;
+ this->size = c;
+ }
va_end( args2 );
}
@@ -138,18 +148,28 @@ struct __str : public LIST<CT> {
return 1;
}
- __str<CT>& fmt( const char* fmt, ... ) {
+ __str<CT>& fmt( const CT* fmt, ... ) {
va_list args;
va_start( args, fmt );
va_list args2;
va_copy( args2, args );
- U32 c = this->size + vsnprintf( 0, 0, fmt, args );
- va_end( args );
- if( c > this->capacity )
- this->reserve( c * 2 );
- vsnprintf( this->data + this->size, c + 1, fmt, args2 );
- this->data[c] = 0;
- this->size = c;
+ if constexpr( sizeof( CT ) == 1 ) {
+ U32 c = this->size + vsnprintf( 0, 0, fmt, args );
+ va_end( args );
+ if( c > this->capacity )
+ this->reserve( c * 2 );
+ vsnprintf( this->data + this->size, c + 1, fmt, args2 );
+ this->data[c] = 0;
+ this->size = c;
+ } else {
+ U32 c = this->size + vswprintf( 0, 0, fmt, args );
+ va_end( args );
+ if( c > this->capacity )
+ this->reserve( c * 2 );
+ vswprintf( this->data + this->size, c + 1, fmt, args2 );
+ this->data[c] = 0;
+ this->size = c;
+ }
va_end( args2 );
return *this;
diff --git a/src/util/typedef.h b/src/util/typedef.h
index 53c4010..4a28624 100644
--- a/src/util/typedef.h
+++ b/src/util/typedef.h
@@ -29,7 +29,11 @@ typedef double F64;
typedef unsigned long PTR;
+// lambda macro - captures all by ref
#define fn( ... ) [&]( __VA_ARGS__ )
+// lambda macro - captures all by copy
+#define cfn( ... ) [=]( __VA_ARGS__ )
+// lambda macro - raw pointer func
#define pfn( ... ) []( __VA_ARGS__ )
template <typename T>