* entity inspector: select entities by key, value, key+value buttons

replaces and complements obscure behavior of SelectAllOfType with entity inspector shown
This commit is contained in:
Garux 2020-08-19 08:23:04 +03:00
parent fdef42427d
commit 2944cff834
5 changed files with 113 additions and 27 deletions

View File

@ -1503,6 +1503,19 @@ void EntityInspector_focusSelected( GtkButton *button, gpointer user_data ){
FocusAllViews();
}
void EntityInspector_selectByKey( GtkButton *button, gpointer user_data ){
Select_EntitiesByKeyValue( gtk_entry_get_text( g_entityKeyEntry ), nullptr );
}
void EntityInspector_selectByValue( GtkButton *button, gpointer user_data ){
Select_EntitiesByKeyValue( nullptr, gtk_entry_get_text( g_entityValueEntry ) );
}
void EntityInspector_selectByKeyValue( GtkButton *button, gpointer user_data ){
Select_EntitiesByKeyValue( gtk_entry_get_text( g_entityKeyEntry ), gtk_entry_get_text( g_entityValueEntry ) );
}
GtkWidget* EntityInspector_constructWindow( GtkWindow* toplevel ){
GtkWidget* vbox = gtk_vbox_new( FALSE, 2 );
gtk_widget_show( vbox );
@ -1663,7 +1676,7 @@ GtkWidget* EntityInspector_constructWindow( GtkWindow* toplevel ){
{
// key/value entry
GtkTable* table = GTK_TABLE( gtk_table_new( 2, 2, FALSE ) );
GtkTable* table = GTK_TABLE( gtk_table_new( 2, 3, FALSE ) );
gtk_widget_show( GTK_WIDGET( table ) );
gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( table ), FALSE, TRUE, 0 );
gtk_table_set_row_spacings( table, 3 );
@ -1708,6 +1721,49 @@ GtkWidget* EntityInspector_constructWindow( GtkWindow* toplevel ){
(GtkAttachOptions)( 0 ), 0, 0 );
gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
}
/* select by key/value buttons */
GtkTable* tab = GTK_TABLE( gtk_table_new( 2, 2, FALSE ) );
gtk_table_attach( table, GTK_WIDGET( tab ), 2, 3, 0, 2,
(GtkAttachOptions)( GTK_FILL ),
(GtkAttachOptions)( 0 ), 0, 0 );
table = tab;
gtk_widget_show( GTK_WIDGET( table ) );
gtk_table_set_row_spacings( table, 0 );
gtk_table_set_col_spacings( table, 0 );
{
GtkWidget* button = gtk_button_new();
gtk_button_set_image( GTK_BUTTON( button ), gtk_image_new_from_stock( GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU ) );
gtk_widget_set_can_focus( button, FALSE );
gtk_widget_set_tooltip_text( button, "Select by key" );
gtk_widget_show( button );
gtk_table_attach( table, button, 0, 1, 0, 1,
(GtkAttachOptions)( GTK_FILL ),
(GtkAttachOptions)( 0 ), 0, 0 );
g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_selectByKey ), 0 );
}
{
GtkWidget* button = gtk_button_new();
gtk_button_set_image( GTK_BUTTON( button ), gtk_image_new_from_stock( GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU ) );
gtk_widget_set_can_focus( button, FALSE );
gtk_widget_set_tooltip_text( button, "Select by value" );
gtk_widget_show( button );
gtk_table_attach( table, button, 0, 1, 1, 2,
(GtkAttachOptions)( GTK_FILL ),
(GtkAttachOptions)( 0 ), 0, 0 );
g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_selectByValue ), 0 );
}
{
GtkWidget* button = gtk_button_new();
gtk_button_set_image( GTK_BUTTON( button ), gtk_image_new_from_stock( GTK_STOCK_APPLY, GTK_ICON_SIZE_MENU ) );
gtk_widget_set_can_focus( button, FALSE );
gtk_widget_set_tooltip_text( button, "Select by key + value" );
gtk_widget_show( button );
gtk_table_attach( table, button, 1, 2, 0, 2,
(GtkAttachOptions)( GTK_FILL ),
(GtkAttachOptions)( GTK_FILL ), 0, 0 );
g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_selectByKeyValue ), 0 );
}
}
{
@ -1755,9 +1811,8 @@ GtkWidget* EntityInspector_constructWindow( GtkWindow* toplevel ){
}
{
GtkWidget* button = gtk_toggle_button_new();
GtkImage* image = GTK_IMAGE( gtk_image_new_from_stock( GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_SMALL_TOOLBAR ) );
gtk_widget_show( GTK_WIDGET( image ) );
gtk_container_add( GTK_CONTAINER( button ), GTK_WIDGET( image ) );
GtkWidget* image = gtk_image_new_from_stock( GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_SMALL_TOOLBAR );
gtk_button_set_image( GTK_BUTTON( button ), image );
gtk_button_set_relief( GTK_BUTTON( button ), GTK_RELIEF_NONE );
gtk_widget_set_can_focus( button, FALSE );
gtk_box_pack_start( hbox, button, FALSE, FALSE, 0 );
@ -1856,13 +1911,3 @@ void EntityInspector_construct(){
void EntityInspector_destroy(){
GlobalEntityClassManager().detach( g_EntityInspector );
}
const char *EntityInspector_getCurrentKey(){
if ( !GroupDialog_isShown() ) {
return 0;
}
if ( GroupDialog_getPage() != g_page_entity ) {
return 0;
}
return gtk_entry_get_text( g_entityKeyEntry );
}

View File

@ -27,6 +27,5 @@ typedef struct _GtkWindow GtkWindow;
GtkWidget* EntityInspector_constructWindow( GtkWindow* parent );
void EntityInspector_construct();
void EntityInspector_destroy();
const char *EntityInspector_getCurrentKey();
#endif

View File

@ -43,7 +43,5 @@ GtkWidget* GroupDialog_addPage( const char* tabLabel, GtkWidget* widget, const S
void GroupDialog_showPage( GtkWidget* page );
void GroupDialog_updatePageTitle( GtkWidget* page );
bool GroupDialog_isShown();
GtkWidget* GroupDialog_getPage();
#endif

View File

@ -725,14 +725,14 @@ bool propertyvalues_contain( const PropertyValues& propertyvalues, const char *s
return false;
}
template<typename EntityMatcher>
class EntityFindByPropertyValueWalker : public scene::Graph::Walker
{
const PropertyValues& m_propertyvalues;
const char *m_prop;
const EntityMatcher& m_entityMatcher;
const scene::Node* m_world;
public:
EntityFindByPropertyValueWalker( const char *prop, const PropertyValues& propertyvalues )
: m_propertyvalues( propertyvalues ), m_prop( prop ), m_world( Map_FindWorldspawn( g_map ) ){
EntityFindByPropertyValueWalker( const EntityMatcher& entityMatcher )
: m_entityMatcher( entityMatcher ), m_world( Map_FindWorldspawn( g_map ) ){
}
bool pre( const scene::Path& path, scene::Instance& instance ) const {
if( !path.top().get().visible() ){
@ -745,7 +745,7 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const {
Entity* entity = Node_getEntity( path.top() );
if ( entity != 0 ){
if( propertyvalues_contain( m_propertyvalues, entity->getKeyValue( m_prop ) ) ) {
if( m_entityMatcher( entity ) ) {
Instance_getSelectable( instance )->setSelected( true );
return true;
}
@ -760,8 +760,15 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const {
}
};
template<typename EntityMatcher>
void Scene_EntitySelectByPropertyValues( scene::Graph& graph, const EntityMatcher& entityMatcher ){
graph.traverse( EntityFindByPropertyValueWalker<EntityMatcher>( entityMatcher ) );
}
void Scene_EntitySelectByPropertyValues( scene::Graph& graph, const char *prop, const PropertyValues& propertyvalues ){
graph.traverse( EntityFindByPropertyValueWalker( prop, propertyvalues ) );
Scene_EntitySelectByPropertyValues( GlobalSceneGraph(), [prop, &propertyvalues]( const Entity* entity )->bool{
return propertyvalues_contain( propertyvalues, entity->getKeyValue( prop ) );
} );
}
class EntityGetSelectedPropertyValuesWalker : public scene::Graph::Walker
@ -841,10 +848,7 @@ void Select_AllOfType(){
else
{
PropertyValues propertyvalues;
const char *prop = EntityInspector_getCurrentKey();
if ( !prop || !*prop ) {
prop = "classname";
}
const char *prop = "classname";
Scene_EntityGetPropertyValues( GlobalSceneGraph(), prop, propertyvalues );
GlobalSelectionSystem().setSelectedAll( false );
if ( !propertyvalues.empty() ) {
@ -858,6 +862,45 @@ void Select_AllOfType(){
}
}
void Select_EntitiesByKeyValue( const char* key, const char* value ){
GlobalSelectionSystem().setSelectedAll( false );
if( key != nullptr && value != nullptr ){
if( !string_empty( key ) && !string_empty( value ) ){
Scene_EntitySelectByPropertyValues( GlobalSceneGraph(), [key, value]( const Entity* entity )->bool{
return string_equal_nocase( entity->getKeyValue( key ), value );
} );
}
}
else if( key != nullptr ){
if( !string_empty( key ) ){
Scene_EntitySelectByPropertyValues( GlobalSceneGraph(), [key]( const Entity* entity )->bool{
return !string_empty( entity->getKeyValue( key ) );
} );
}
}
else if( value != nullptr ){
if( !string_empty( value ) ){
Scene_EntitySelectByPropertyValues( GlobalSceneGraph(), [value]( const Entity* entity )->bool{
class Visitor : public Entity::Visitor
{
const char* const m_value;
public:
bool m_found = false;
Visitor( const char* value ) : m_value( value ){
}
void visit( const char* key, const char* value ){
if ( string_equal_nocase( m_value, value ) ) {
m_found = true;
}
}
} visitor( value );
entity->forEachKeyValue( visitor );
return visitor.m_found;
} );
}
}
}
void Select_FacesAndPatchesByShader(){
Scene_BrushFacesSelectByShader( GlobalSceneGraph(), TextureBrowser_GetSelectedShader() );
Scene_PatchSelectByShader( GlobalSceneGraph(), TextureBrowser_GetSelectedShader() );

View File

@ -38,6 +38,7 @@ void Selection_MoveDown();
void Selection_MoveUp();
void Select_AllOfType();
void Select_EntitiesByKeyValue( const char* key, const char* value );
void Select_ConnectedEntities( bool targeting, bool targets, bool focus );
void SelectConnectedEntities();