/* Copyright (C) 1999-2007 id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // // Floating dialog that contains a notebook with at least Entities and Group tabs // I merged the 2 MS Windows dialogs in a single class // // Leonardo Zide (leo@lokigames.com) // #ifndef _WIN32 #include #endif #include #include #include "stdafx.h" #include "groupdialog.h" GtkWidget* EntWidgets[EntLast]; GtkListStore* g_entlist_store; GtkListStore* g_entprops_store; int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE qboolean multiple_entities; qboolean disable_spawn_get = false; entity_t *edit_entity; /* static GdkPixmap *tree_pixmaps[7]; static GdkBitmap *tree_masks[7]; */ #define IMG_PATCH 0 #define IMG_BRUSH 1 #define IMG_GROUP 2 #define IMG_ENTITY 3 #define IMG_ENTITYGROUP 4 #define IMG_MODEL 5 #define IMG_SCRIPT 6 // misc group support #define MAX_GROUPS 4096 #define GROUP_DELIMETER '@' #define GROUPNAME "QER_Group_%i" GroupDlg g_wndGroup; GroupDlg *g_pGroupDlg = &g_wndGroup; // group_t are loaded / saved through "group_info" entities // they hold epairs for group settings and additionnal access info (tree nodes) group_t *g_pGroups = NULL; // the number of active spawnflags static int spawnflag_count; // table: index, match spawnflag item to the spawnflag index (i.e. which bit) static int spawn_table[MAX_FLAGS]; // we change the layout depending on how many spawn flags we need to display // the table is a 4x4 in which we need to put the comment box EntWidgets[EntComment] and the spawn flags.. static GtkWidget *LayoutTable; // 0: none of them are hooked // 1: only the text, 2: text and four checks, 3: text and 8 checks static int widget_state = 0; static void entity_check( GtkWidget *widget, gpointer data ); // ============================================================================= // Global functions /* =============================================================== ENTITY WINDOW =============================================================== */ void FillClassList(){ GtkListStore* store = g_entlist_store; gtk_list_store_clear( store ); for ( eclass_t* e = eclass ; e ; e = e->next ) { GtkTreeIter iter; gtk_list_store_append( store, &iter ); gtk_list_store_set( store, &iter, 0, e->name, 1, e, -1 ); } } // SetKeyValuePairs // // Reset the key/value (aka property) listbox and fill it with the // k/v pairs from the entity being edited. // void SetKeyValuePairs( bool bClearMD3 ){ GtkListStore* store = g_entprops_store; gtk_list_store_clear( store ); if ( edit_entity == NULL ) { // if there's no entity, then display no key/values return; } // save current key/val pair around filling epair box // row_select wipes it and sets to first in list Str strKey = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) ); Str strVal = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntValueField] ) ); // Walk through list and add pairs for ( epair_t* epair = edit_entity->epairs ; epair ; epair = epair->next ) { GtkTreeIter iter; gtk_list_store_append( store, &iter ); gtk_list_store_set( store, &iter, 0, epair->key, 1, epair->value, -1 ); } gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), strKey.GetBuffer() ); gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), strVal.GetBuffer() ); Sys_UpdateWindows( W_CAMERA | W_XY ); } // SetSpawnFlags // // Update the checkboxes to reflect the flag state of the entity // void SetSpawnFlags( void ){ int f, i, v; disable_spawn_get = true; f = atoi( ValueForKey( edit_entity, "spawnflags" ) ); for ( i = 0 ; i < spawnflag_count ; i++ ) { v = !!( f & ( 1 << spawn_table[i] ) ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( EntWidgets[EntCheck1 + i] ), v ); } // take care of the remaining ones for ( i = spawnflag_count ; i < MAX_FLAGS ; i++ ) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( EntWidgets[EntCheck1 + i] ), FALSE ); } disable_spawn_get = false; } // GetSpawnFlags // // Update the entity flags to reflect the state of the checkboxes // // NOTE: this function had a tendency to add "spawnflags" "0" on most entities // if this wants to set spawnflags to zero, remove the key void GetSpawnFlags( void ){ int f, i, v; char sz[32]; f = 0; for ( i = 0 ; i < spawnflag_count ; i++ ) { v = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( EntWidgets[EntCheck1 + i] ) ); f |= v << spawn_table[i]; } if ( f == 0 ) { // remove all "spawnflags" keys if ( multiple_entities ) { brush_t *b; for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) DeleteKey( b->owner, "spawnflags" ); } else{ DeleteKey( edit_entity, "spawnflags" ); } } else { sprintf( sz, "%i", f ); if ( multiple_entities ) { brush_t *b; for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) SetKeyValue( b->owner, "spawnflags", sz ); } else{ SetKeyValue( edit_entity, "spawnflags", sz ); } } SetKeyValuePairs(); } //#define DBG_UPDATESEL // UpdateSel // // Update the listbox, checkboxes and k/v pairs to reflect the new selection // iIndex is the index in the list box with the class name, -1 if not found bool UpdateSel( int iIndex, eclass_t *pec ){ int i, next_state; brush_t *b; // syndrom of crappy code, we may get into stack overflowing crap with this function and Gtk // if we play with the list of entity classes // using a static flag to prevent recursion static bool bBlockUpdate = false; if ( bBlockUpdate ) { return FALSE; // NOTE TTimo wtf is the return value for anyway? } #ifdef DBG_UPDATESEL Sys_FPrintf( SYS_WRN, "UpdateSel\n" ); #endif if ( selected_brushes.next == &selected_brushes ) { edit_entity = world_entity; multiple_entities = false; } else { edit_entity = selected_brushes.next->owner; for ( b = selected_brushes.next->next ; b != &selected_brushes ; b = b->next ) { if ( b->owner != edit_entity ) { multiple_entities = true; break; } } } if ( iIndex != -1 ) { #ifdef DBG_UPDATESEL Sys_FPrintf( SYS_WRN,"Setting focus_row to %d\n", iIndex ); #endif bBlockUpdate = true; GtkTreeView* view = GTK_TREE_VIEW( EntWidgets[EntList] ); GtkTreePath* path = gtk_tree_path_new(); gtk_tree_path_append_index( path, iIndex ); gtk_tree_selection_select_path( gtk_tree_view_get_selection( view ), path ); gtk_tree_view_scroll_to_cell( view, path, NULL, FALSE, 0, 0 ); gtk_tree_path_free( path ); bBlockUpdate = false; } if ( pec == NULL ) { return TRUE; } // Set up the description { GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( EntWidgets[EntComment] ) ); gtk_text_buffer_set_text( buffer, pec->comments, -1 ); } spawnflag_count = 0; // do a first pass to count the spawn flags, don't touch the widgets, we don't know in what state they are for ( i = 0 ; i < MAX_FLAGS ; i++ ) { if ( pec->flagnames[i] && pec->flagnames[i][0] != 0 && strcmp( pec->flagnames[i],"-" ) ) { spawn_table[spawnflag_count] = i; spawnflag_count++; } } // what's new widget state if ( spawnflag_count == 0 ) { next_state = 1; } else if ( spawnflag_count <= 4 ) { next_state = 2; } else if ( spawnflag_count <= 8 ) { next_state = 3; } else if ( spawnflag_count <= 12 ) { next_state = 4; } else{ next_state = 5; } widget_state = next_state; static int last_count = 0; // disable all remaining boxes // NOTE: these boxes might not even be on display for ( i = 0; i < last_count; i++ ) { GtkWidget* widget = EntWidgets[EntCheck1 + i]; gtk_label_set_text( GTK_LABEL( GTK_BIN( widget )->child ), " " ); gtk_widget_hide( widget ); gtk_widget_ref( widget ); gtk_container_remove( GTK_CONTAINER( LayoutTable ), widget ); } last_count = spawnflag_count; for ( i = 0 ; i < spawnflag_count ; i++ ) { GtkWidget* widget = EntWidgets[EntCheck1 + i]; gtk_widget_show( widget ); Str str; str = pec->flagnames[spawn_table[i]]; str.MakeLower(); // gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1, gtk_table_attach( GTK_TABLE( LayoutTable ), widget, i % 4, i % 4 + 1, i / 4, i / 4 + 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); gtk_widget_unref( widget ); gtk_label_set_text( GTK_LABEL( GTK_BIN( widget )->child ), str.GetBuffer() ); } SetSpawnFlags(); SetKeyValuePairs(); return TRUE; } bool UpdateEntitySel( eclass_t *pec ){ #ifdef DBG_UPDATESEL Sys_FPrintf( SYS_WRN, "UpdateEntitySel\n" ); #endif GtkTreeModel* model = GTK_TREE_MODEL( g_entlist_store ); GtkTreeIter iter; unsigned int i = 0; for ( gboolean good = gtk_tree_model_get_iter_first( model, &iter ); good != FALSE; good = gtk_tree_model_iter_next( model, &iter ) ) { char* text; gtk_tree_model_get( model, &iter, 0, &text, -1 ); if ( strcmp( text, pec->name ) == 0 ) { #ifdef DBG_UPDATESEL Sys_FPrintf( SYS_WRN, "found a match: %d %s\n", i, pec->name ); #endif return UpdateSel( i, pec ); } g_free( text ); ++i; } return UpdateSel( -1, pec ); } // CreateEntity // // Creates a new entity based on the currently selected brush and entity type. // void CreateEntity( void ){ GtkTreeView* view = GTK_TREE_VIEW( EntWidgets[EntList] ); // check to make sure we have a brush if ( selected_brushes.next == &selected_brushes ) { gtk_MessageBox( g_pParentWnd->m_pWidget, "You must have a selected brush to create an entity", "info" ); return; } // find out what type of entity we are trying to create GtkTreeModel* model; GtkTreeIter iter; if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( view ), &model, &iter ) == FALSE ) { gtk_MessageBox( g_pParentWnd->m_pWidget, "You must have a selected class to create an entity", "info" ); return; } char* text; gtk_tree_model_get( model, &iter, 0, &text, -1 ); CreateEntityFromName( text, vec3_origin ); g_free( text ); if ( selected_brushes.next == &selected_brushes ) { edit_entity = world_entity; } else{ edit_entity = selected_brushes.next->owner; } SetKeyValuePairs(); Select_Deselect(); Select_Brush( edit_entity->brushes.onext ); Sys_UpdateWindows( W_ALL ); } /* =============== AddProp =============== */ void AddProp(){ if ( edit_entity == NULL ) { return; } // Get current selection text const char* key = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) ); const char* value = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntValueField] ) ); // TTimo: if you change the classname to worldspawn you won't merge back in the structural brushes but create a parasite entity if ( !strcmp( key, "classname" ) && !strcmp( value, "worldspawn" ) ) { gtk_MessageBox( g_pParentWnd->m_pWidget, "Cannot change \"classname\" key back to worldspawn.", NULL, MB_OK ); return; } // RR2DO2: we don't want spaces in entity keys if ( strstr( key, " " ) ) { gtk_MessageBox( g_pParentWnd->m_pWidget, "No spaces are allowed in entity keys.", NULL, MB_OK ); return; } if ( multiple_entities ) { brush_t *b; for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) SetKeyValue( b->owner, key, value ); } else{ SetKeyValue( edit_entity, key, value ); } // refresh the prop listbox SetKeyValuePairs(); #ifdef USEPLUGINENTITIES // if it's a plugin entity, perhaps we need to update some drawing parameters // NOTE: perhaps moving this code to a seperate func would help if we need it in other places // TODO: we need to call some update func in the IPluginEntity in case model name changes etc. // ( for the moment only bounding brush is updated ), see UpdateModelBrush in Ritual's Q3Radiant if ( edit_entity->eclass->nShowFlags & ECLASS_PLUGINENTITY ) { vec3_t mins, maxs; edit_entity->pPlugEnt->GetBounds( mins, maxs ); // replace old bounding brush by newly computed one // NOTE: this part is similar to Entity_BuildModelBrush in Ritual's Q3Radiant, it can be // usefull moved into a seperate func brush_t *b,*oldbrush; if ( edit_entity->brushes.onext != &edit_entity->brushes ) { oldbrush = edit_entity->brushes.onext; } b = Brush_Create( mins, maxs, &edit_entity->eclass->texdef ); Entity_LinkBrush( edit_entity, b ); Brush_Build( b, true ); Select_Deselect(); Brush_AddToList( edit_entity->brushes.onext, &selected_brushes ); if ( oldbrush ) { Brush_Free( oldbrush ); } } #endif // USEPLUGINENTITIES } /* =============== DelProp =============== */ void DelProp( void ){ if ( edit_entity == NULL ) { return; } // Get current selection text const char* key = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) ); if ( multiple_entities ) { brush_t *b; for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) DeleteKey( b->owner, key ); } else{ DeleteKey( edit_entity, key ); } // refresh the prop listbox SetKeyValuePairs(); } void ResetEntity(){ epair_t *pep; int i; if ( edit_entity == NULL ) { return; } if ( multiple_entities ) { brush_t *b; for ( b = selected_brushes.next; b != &selected_brushes; b = b->next ) for ( pep = b->owner->epairs; pep; ) { if ( strcmp( pep->key, "classname" ) != 0 ) { DeleteKey( b->owner, pep->key ); pep = b->owner->epairs; } else{ pep = pep->next; } } } else{ for ( pep = edit_entity->epairs; pep; ) { if ( strcmp( pep->key, "classname" ) != 0 ) { DeleteKey( edit_entity, pep->key ); pep = edit_entity->epairs; } else{ pep = pep->next; } } } // refresh the dialog SetKeyValuePairs(); for ( i = EntCheck1; i <= EntCheck16; i++ ) gtk_signal_handler_block_by_func( GTK_OBJECT( EntWidgets[i] ), GTK_SIGNAL_FUNC( entity_check ), NULL ); SetSpawnFlags(); for ( i = EntCheck1; i <= EntCheck16; i++ ) gtk_signal_handler_unblock_by_func( GTK_OBJECT( EntWidgets[i] ), GTK_SIGNAL_FUNC( entity_check ), NULL ); } bool GetSelectAllCriteria( CString &strKey, CString &strVal ){ GtkTreeModel* model; GtkTreeIter iter; if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( GTK_TREE_VIEW( EntWidgets[EntProps] ) ), &model, &iter ) && ( inspector_mode == W_ENTITY ) && GTK_WIDGET_VISIBLE( g_pGroupDlg->m_pWidget ) ) { strKey = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) ); strVal = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntValueField] ) ); return TRUE; } return FALSE; } void AssignSound(){ char buffer[NAME_MAX]; strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() ); strcat( buffer, "sound/" ); if ( access( buffer, R_OK ) != 0 ) { // just go to fsmain strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() ); strcat( buffer, "/" ); } const char *filename = file_dialog( g_pGroupDlg->m_pWidget, TRUE, _( "Open Wav File" ), buffer, "sound" ); if ( filename != NULL ) { gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), "noise" ); char *aux = vfsExtractRelativePath( filename ); CString str; if ( aux ) { str = aux; } else { Sys_FPrintf( SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n" ); str = filename; } gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), str.GetBuffer() ); AddProp(); } } void AssignModel(){ char buffer[NAME_MAX]; strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() ); strcat( buffer, "models/" ); if ( access( buffer, R_OK ) != 0 ) { // just go to fsmain strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() ); strcat( buffer, "/" ); } const char *filename = file_dialog( g_pGroupDlg->m_pWidget, TRUE, _( "Open Model" ), buffer, MODEL_MAJOR ); if ( filename != NULL ) { gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), "model" ); // use VFS to get the correct relative path char *aux = vfsExtractRelativePath( filename ); CString str; if ( aux ) { str = aux; } else { Sys_FPrintf( SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n" ); str = filename; } gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), str.GetBuffer() ); AddProp(); edit_entity->brushes.onext->bModelFailed = false; } } /* ============== SetInspectorMode ============== */ void SetInspectorMode( int iType ){ if ( iType == W_GROUP ) { gtk_MessageBox( g_pParentWnd->m_pWidget, "Brush grouping is not functional yet", NULL, MB_OK | MB_ICONWARNING ); } if ( !g_pParentWnd->FloatingGroupDialog() && ( iType == W_TEXTURE || iType == W_CONSOLE ) ) { return; } // Is the caller asking us to cycle to the next window? if ( iType == -1 ) { if ( inspector_mode == W_ENTITY ) { iType = W_TEXTURE; } else if ( inspector_mode == W_TEXTURE ) { iType = W_CONSOLE; } else if ( inspector_mode == W_CONSOLE ) { iType = W_GROUP; } else{ iType = W_ENTITY; } } switch ( iType ) { case W_ENTITY: // entity is always first in the inspector gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_entity ), "Entities" ); gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 0 ); break; case W_TEXTURE: g_pParentWnd->GetTexWnd()->FocusEdit(); gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_entity ), "Textures" ); if ( g_pParentWnd->FloatingGroupDialog() ) { // if the notebook page is already at 1, no expose event fires up on the embedded GLWindow, leading in the texture window not drawing // I did witness an expose event on the notebook widget though, but for some reason it's not traveling down.. // so when hiding the group dialog, we are setting the page to 0, the page switch does an expose and triggers drawing.. (see OnDialogKey) gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 1 ); // FIXME: https://github.com/TTimo/GtkRadiant/issues/192 // Sys_Printf( "show widget: set page to 1\n" ); } break; case W_CONSOLE: gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_entity ), "Console" ); if ( g_pParentWnd->FloatingGroupDialog() ) { gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 2 ); } break; case W_GROUP: if ( g_pParentWnd->FloatingGroupDialog() ) { gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 3 ); } else { gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 1 ); } break; default: break; } } void Group_Add( entity_t *e ){ /* group_t *g = (group_t*)qmalloc(sizeof(group_t)); g->epairs = e->epairs; g->next = NULL; e->epairs = NULL; // create a new group node char *text = ValueForKey(g->epairs, "group"); g->itemOwner = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_wndGroup.m_hWorld, NULL, &text, 0, tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], TRUE, TRUE); g->next = g_pGroups; g_pGroups = g; */ } /* group_t* Group_Alloc(char *name) { group_t *g = (group_t*)qmalloc(sizeof(group_t)); SetKeyValue( g->epairs, "group", name ); return g; } group_t* Group_ForName(const char * name) { group_t *g = g_pGroups; while (g != NULL) { if (strcmp( ValueForKey(g->epairs,"group"), name ) == 0) break; g = g->next; } return g; } void Group_AddToItem(brush_t *b, GtkCTreeNode* item) { int nImage = IMG_BRUSH; if (!g_qeglobals.m_bBrushPrimitMode) { return; } const char *pName = NULL; // const char *pNamed = Brush_GetKeyValue(b, "name"); if (!b->owner || (b->owner == world_entity)) { if (b->patchBrush) { pName = "Generic Patch"; nImage = IMG_PATCH; } else { pName = "Generic Brush"; nImage = IMG_BRUSH; } } else { pName = b->owner->eclass->name; if (b->owner->eclass->fixedsize) { nImage = IMG_ENTITY; } else { nImage = IMG_ENTITYGROUP; } } GtkCTreeNode *newItem; int i = (b->patchBrush) ? IMG_PATCH : IMG_BRUSH; newItem = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), item, NULL, (gchar**)&pName, 0, tree_pixmaps[i], tree_masks[i], tree_pixmaps[i], tree_masks[i], TRUE, TRUE); gtk_ctree_node_set_row_data (GTK_CTREE (g_wndGroup.m_pTree), newItem, b); b->itemOwner = newItem; } */ void Group_RemoveBrush( brush_t *b ){ /* if (!g_qeglobals.m_bBrushPrimitMode) { return; } if (b->itemOwner) { gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); b->itemOwner = NULL; } DeleteKey(b->epairs, "group"); */ } /* void Group_AddToWorld(brush_t *b) { if (!g_qeglobals.m_bBrushPrimitMode) { return; } GtkCTreeNode *parent = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); Group_AddToItem(b, parent); } */ void Group_AddToProperGroup( brush_t *b ){ /* if (!g_qeglobals.m_bBrushPrimitMode) { return; } // NOTE: we do a local copy of the "group" key because it gets erased by Group_RemoveBrush const char *pGroup = Brush_GetKeyValue(b, "group"); // remove the entry in the tree if there's one if (b->itemOwner) { gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner); b->itemOwner = NULL; } if (*pGroup != 0) { // find the item group_t *g = Group_ForName(pGroup); if (g) Group_AddToItem(b, g->itemOwner); #ifdef _DEBUG else Sys_Printf("WARNING: unexpected Group_ForName not found in Group_AddToProperGroup\n"); #endif } else { Group_AddToWorld(b); } */ } /* void Group_AddToSelected(brush_t *b) { if (!g_qeglobals.m_bBrushPrimitMode) { return; } GtkCTreeNode *item; item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), GTK_CLIST (g_pGroupDlg->m_pTree)->focus_row); if (item == NULL) { item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0); } Group_AddToItem(b, item); } */ /* void Group_Save(FILE *f) { group_t *g = g_pGroups; while (g) { fprintf(f,"{\n\"classname\" \"group_info\"\n\"group\" \"%s\"\n}\n", ValueForKey( g->epairs, "group" )); g = g->next; } } */ void Group_Init(){ if ( !g_qeglobals.m_bBrushPrimitMode ) { return; } // start by cleaning everything // clean the groups //++timo FIXME: we leak, delete the groups on the way (I don't have time to do it now) #ifdef _DEBUG Sys_Printf( "TODO: fix leak in Group_Init\n" ); #endif group_t *g = g_pGroups; while ( g ) { epair_t *ep,*enext; for ( ep = g->epairs ; ep ; ep = enext ) { enext = ep->next; free( ep->key ); free( ep->value ); free( ep ); } g = g->next; } /* GtkCTreeNode *world; char *text = "World"; g_pGroups = NULL; gtk_clist_clear (GTK_CLIST (g_wndGroup.m_pTree)); world = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), NULL, NULL, &text, 0, tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], FALSE, TRUE); */ // walk through all the brushes, remove the itemOwner key and add them back where they belong brush_t *b; for ( b = active_brushes.next; b != &active_brushes; b = b->next ) { b->itemOwner = NULL; Group_AddToProperGroup( b ); } for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) { b->itemOwner = NULL; Group_AddToProperGroup( b ); } } /* // scan through world_entity for groups in this map? // we use GROUPNAME "QER_group_%i" to look for existing groups and their naming //++timo FIXME: is this actually needed for anything? void Group_GetListFromWorld(GSList **pArray) { if (!g_qeglobals.m_bBrushPrimitMode) { return; } if (world_entity == NULL) { return; } char cBuff[1024]; for (int i =0; i < MAX_GROUPS; i++) { sprintf(cBuff, GROUPNAME, i); char *pGroup = ValueForKey(world_entity, cBuff); if (pGroup && strlen(pGroup) > 0) { *pArray = g_slist_append (*pArray, g_strdup (pGroup)); } else { break; } } } void Group_RemoveListFromWorld() { if (!g_qeglobals.m_bBrushPrimitMode) { return; } GSList* array = NULL; Group_GetListFromWorld(&array); while (array) { DeleteKey(world_entity, (char*)array->data); g_free (array->data); array = g_slist_remove (array, array->data); } } int CountChar(const char *p, char c) { int nCount = 0; int nLen = strlen(p)-1; while (nLen-- >= 0) { if (p[nLen] == c) { nCount++; } } return nCount; } */ // ============================================================================= // callbacks static void eclasslist_selection_changed( GtkTreeSelection* selection, gpointer data ){ GtkTreeModel* model; GtkTreeIter selected; // no world entity, we are not ready yet if ( !world_entity ) { return; } if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) { eclass_t* eclass; gtk_tree_model_get( model, &selected, 1, &eclass, -1 ); if ( eclass != NULL ) { GtkTreePath* path = gtk_tree_model_get_path( model, &selected ); UpdateSel( gtk_tree_path_get_indices( path )[0], eclass ); gtk_tree_path_free( path ); } } } static gint eclasslist_button_press( GtkWidget *widget, GdkEventButton *event, gpointer data ){ if ( event->type == GDK_2BUTTON_PRESS ) { CreateEntity(); return TRUE; } return FALSE; } static gint eclasslist_keypress( GtkWidget* widget, GdkEventKey* event, gpointer data ){ unsigned int code = gdk_keyval_to_upper( event->keyval ); if ( event->keyval == GDK_Return ) { CreateEntity(); return TRUE; } // select the entity that starts with the key pressed if ( code <= 'Z' && code >= 'A' ) { GtkTreeView* view = GTK_TREE_VIEW( EntWidgets[EntList] ); GtkTreeModel* model; GtkTreeIter iter; if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( view ), &model, &iter ) == FALSE || gtk_tree_model_iter_next( model, &iter ) == FALSE ) { gtk_tree_model_get_iter_first( model, &iter ); } for ( unsigned int count = gtk_tree_model_iter_n_children( model, NULL ); count > 0; --count ) { char* text; gtk_tree_model_get( model, &iter, 0, &text, -1 ); if ( toupper( text[0] ) == (int)code ) { GtkTreePath* path = gtk_tree_model_get_path( model, &iter ); gtk_tree_selection_select_path( gtk_tree_view_get_selection( view ), path ); gtk_tree_view_scroll_to_cell( view, path, NULL, FALSE, 0, 0 ); gtk_tree_path_free( path ); count = 1; } g_free( text ); if ( gtk_tree_model_iter_next( model, &iter ) == FALSE ) { gtk_tree_model_get_iter_first( model, &iter ); } } return TRUE; } return FALSE; } static void proplist_selection_changed( GtkTreeSelection* selection, gpointer data ){ // find out what type of entity we are trying to create GtkTreeModel* model; GtkTreeIter iter; if ( gtk_tree_selection_get_selected( selection, &model, &iter ) == FALSE ) { return; } char* key; char* val; gtk_tree_model_get( model, &iter, 0, &key, 1, &val, -1 ); gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), key ); gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), val ); g_free( key ); g_free( val ); } static void entity_check( GtkWidget *widget, gpointer data ){ if ( !disable_spawn_get ) { GetSpawnFlags(); } } static void entitylist_angle( GtkWidget *widget, gpointer data ){ SetKeyValue( edit_entity, "angle", (char*)data ); SetKeyValuePairs(); } static gint entityentry_keypress( GtkWidget* widget, GdkEventKey* event, gpointer data ){ if ( event->keyval == GDK_Tab ) { if ( widget == EntWidgets[EntKeyField] ) { //gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), ""); gtk_window_set_focus( GTK_WINDOW( g_pGroupDlg->m_pWidget ), EntWidgets[EntValueField] ); } else{ gtk_window_set_focus( GTK_WINDOW( g_pGroupDlg->m_pWidget ), EntWidgets[EntKeyField] ); } return TRUE; } else if ( event->keyval == GDK_Return ) { if ( widget == EntWidgets[EntKeyField] ) { gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), "" ); gtk_window_set_focus( GTK_WINDOW( g_pGroupDlg->m_pWidget ), EntWidgets[EntValueField] ); } else { AddProp(); } return TRUE; } return FALSE; } static void switch_page( GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data ){ char *text; gtk_label_get( GTK_LABEL( gtk_notebook_get_tab_label( notebook, gtk_notebook_get_nth_page( notebook, page_num ) ) ), &text ); gtk_window_set_title( GTK_WINDOW( data ), text ); gpointer item = g_object_get_data( G_OBJECT( g_pParentWnd->m_pWidget ), "menu_misc_selectentitycolor" ); if ( g_pParentWnd->FloatingGroupDialog() ) { switch ( page_num ) { case 0: inspector_mode = W_ENTITY; break; case 1: inspector_mode = W_TEXTURE; break; case 2: inspector_mode = W_CONSOLE; break; default: inspector_mode = W_GROUP; break; } } else { if ( page_num == 0 ) { inspector_mode = W_ENTITY; } else{ inspector_mode = W_GROUP; } } if ( inspector_mode == W_ENTITY ) { gtk_widget_set_sensitive( GTK_WIDGET( item ), TRUE ); } else{ gtk_widget_set_sensitive( GTK_WIDGET( item ), FALSE ); } } // ============================================================================= // GroupDlg class static gint OnDeleteHide( GtkWidget *widget ) { gtk_widget_hide( widget ); // see OnDialogKey gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 0 ); return TRUE; } // NOTE: when a key is hit with group window focused, we catch in this handler but it gets propagated to mainframe too // therefore the message will be intercepted and used as a ID_SELECTION_DESELECT static gint OnDialogKey( GtkWidget* widget, GdkEventKey* event, gpointer data ) { // make the "ViewTextures" and "ViewEntityInfo" keys that normally bring this dialog up hide it as well - copypasta from mainframe_keypress // NOTE: maybe we could also check the state of the notebook, see if those are actually displayed .. if they are not, then switch the notebook pages rather than hiding? bool hide = false; // Disable this, it makes the dialog hide whenever you type 'T' when editing entities etc. - Esc key is enough #if 0 unsigned int code = gdk_keyval_to_upper( event->keyval ); for ( int i = 0; i < g_nCommandCount; i++ ) { if ( g_Commands[i].m_nKey == code ) { // find a match? // check modifiers unsigned int nState = 0; if ( Sys_AltDown() ) { nState |= RAD_ALT; } if ( ( event->state & GDK_CONTROL_MASK ) != 0 ) { nState |= RAD_CONTROL; } if ( ( event->state & GDK_SHIFT_MASK ) != 0 ) { nState |= RAD_SHIFT; } if ( ( g_Commands[i].m_nModifiers & 0x7 ) == nState ) { Sys_Printf( "Floating group dialog: %s\n", g_Commands[i].m_strCommand ); if ( g_Commands[i].m_nCommand == ID_VIEW_TEXTURE || g_Commands[i].m_nCommand == ID_VIEW_ENTITY ) { hide = true; } break; } } } #endif if ( g_pParentWnd->CurrentStyle() != MainFrame::eFloating && ( hide || event->keyval == GDK_Escape ) ) { // toggle off the group view (whatever part of it is currently displayed) // this used to be done with a g_pParentWnd->OnViewEntity(); but it had bad consequences gtk_widget_hide( widget ); // set the group notebook page back to 0, so that when we recall the texture view there is an expose event coming up gtk_notebook_set_current_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 0 ); // FIXME: https://github.com/TTimo/GtkRadiant/issues/192 // Sys_Printf( "hide widget and set page to 0\n" ); return TRUE; } return FALSE; } GroupDlg::GroupDlg (){ m_pWidget = NULL; m_hWorld = NULL; } #ifdef _WIN32 extern void PositionWindowOnPrimaryScreen( window_position_t& position ); #endif void GroupDlg::Create(){ if ( m_pWidget != NULL ) { return; } GtkWidget* dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL ); #ifdef _WIN32 if ( g_PrefsDlg.m_bStartOnPrimMon ) { PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posEntityWnd ); } #endif load_window_pos( dlg, g_PrefsDlg.mWindowInfo.posEntityWnd ); gtk_window_set_title( GTK_WINDOW( dlg ), "Entities" ); gtk_signal_connect( GTK_OBJECT( dlg ), "delete_event", GTK_SIGNAL_FUNC( OnDeleteHide ), NULL ); // catch 'Esc' gtk_signal_connect( GTK_OBJECT( dlg ), "key_press_event", GTK_SIGNAL_FUNC( OnDialogKey ), NULL ); gtk_window_set_transient_for( GTK_WINDOW( dlg ), GTK_WINDOW( g_pParentWnd->m_pWidget ) ); g_qeglobals_gui.d_entity = dlg; { GtkWidget* notebook = gtk_notebook_new(); gtk_widget_show( notebook ); gtk_container_add( GTK_CONTAINER( dlg ), notebook ); gtk_notebook_set_tab_pos( GTK_NOTEBOOK( notebook ), GTK_POS_BOTTOM ); m_pNotebook = notebook; { GtkWidget* vbox = gtk_vbox_new( FALSE, 2 ); gtk_widget_show( vbox ); gtk_container_set_border_width( GTK_CONTAINER( vbox ), 2 ); { GtkWidget* label = gtk_label_new( "Entities" ); gtk_widget_show( label ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), vbox, label ); } { GtkWidget* split1 = gtk_vpaned_new(); gtk_box_pack_start( GTK_BOX( vbox ), split1, TRUE, TRUE, 0 ); gtk_widget_show( split1 ); { GtkWidget* split2 = gtk_vpaned_new(); gtk_paned_add1( GTK_PANED( split1 ), split2 ); gtk_widget_show( split2 ); g_object_set_data( G_OBJECT( dlg ), "split1", split1 ); g_object_set_data( G_OBJECT( dlg ), "split2", split2 ); { GtkWidget* vbox2 = gtk_vbox_new( FALSE, 2 ); gtk_widget_show( vbox2 ); gtk_paned_pack2( GTK_PANED( split1 ), vbox2, FALSE, FALSE ); { GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL ); gtk_widget_show( scr ); gtk_paned_add1( GTK_PANED( split2 ), scr ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS ); gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN ); { GtkListStore* store = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER ); GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) ); gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE ); g_signal_connect( G_OBJECT( view ), "button_press_event", G_CALLBACK( eclasslist_button_press ), NULL ); g_signal_connect( G_OBJECT( view ), "key_press_event", G_CALLBACK( eclasslist_keypress ), this ); { GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "Key", renderer, "text", 0, (char *) NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column ); } { GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) ); g_signal_connect( G_OBJECT( selection ), "changed", G_CALLBACK( eclasslist_selection_changed ), dlg ); } gtk_widget_show( view ); gtk_container_add( GTK_CONTAINER( scr ), view ); g_object_unref( G_OBJECT( store ) ); EntWidgets[EntList] = view; g_entlist_store = store; } } { GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL ); gtk_widget_show( scr ); gtk_paned_add2( GTK_PANED( split2 ), scr ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS ); gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN ); { GtkWidget* text = gtk_text_view_new(); gtk_widget_set_size_request( text, 0, -1 ); // allow shrinking gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text ), GTK_WRAP_WORD ); gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE ); gtk_widget_show( text ); gtk_container_add( GTK_CONTAINER( scr ), text ); EntWidgets[EntComment] = text; } } { // Spawnflags (4 colums wide max, or window gets too wide.) LayoutTable = gtk_table_new( 4, 4, FALSE ); gtk_box_pack_start( GTK_BOX( vbox2 ), LayoutTable, FALSE, TRUE, 0 ); gtk_widget_show( LayoutTable ); for ( int i = 0; i < MAX_FLAGS; i++ ) { GtkWidget* check = gtk_check_button_new_with_label( "" ); gtk_widget_ref( check ); gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL ); EntWidgets[EntCheck1 + i] = check; } if ( g_pGameDescription->quake2 ) { GtkWidget *check = gtk_check_button_new_with_label( _( "!Easy" ) ); gtk_widget_show( check ); gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL ); EntWidgets[EntCheck17] = check; check = gtk_check_button_new_with_label( _( "!Medium" ) ); gtk_widget_show( check ); gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL ); EntWidgets[EntCheck18] = check; check = gtk_check_button_new_with_label( _( "!Hard" ) ); gtk_widget_show( check ); gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL ); EntWidgets[EntCheck19] = check; check = gtk_check_button_new_with_label( _( "!DeathMatch" ) ); gtk_widget_show( check ); gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL ); EntWidgets[EntCheck20] = check; } } { GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL ); gtk_widget_show( scr ); gtk_box_pack_start( GTK_BOX( vbox2 ), scr, TRUE, TRUE, 0 ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN ); { GtkListStore* store = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_STRING ); GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) ); gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE ); { GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "", renderer, "text", 0, (char *) NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column ); } { GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "", renderer, "text", 1, (char *) NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column ); } { GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) ); g_signal_connect( G_OBJECT( selection ), "changed", G_CALLBACK( proplist_selection_changed ), dlg ); } gtk_widget_show( view ); gtk_container_add( GTK_CONTAINER( scr ), view ); g_object_unref( G_OBJECT( store ) ); EntWidgets[EntProps] = view; g_entprops_store = store; } } } int x = g_PrefsDlg.mWindowInfo.nEntitySplit1; if ( x != -1 ) { gtk_paned_set_position( GTK_PANED( split1 ), x ); while ( gtk_events_pending() ) gtk_main_iteration(); x = g_PrefsDlg.mWindowInfo.nEntitySplit2; if ( x != -1 ) { gtk_paned_set_position( GTK_PANED( split2 ), x ); } } } } { GtkWidget* table = gtk_table_new( 2, 2, FALSE ); gtk_widget_show( table ); gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 ); gtk_table_set_row_spacings( GTK_TABLE( table ), 3 ); gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); { GtkWidget* entry = gtk_entry_new(); gtk_widget_show( entry ); gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1, (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); gtk_widget_set_events( entry, GDK_KEY_PRESS_MASK ); gtk_signal_connect( GTK_OBJECT( entry ), "key_press_event", GTK_SIGNAL_FUNC( entityentry_keypress ), this ); EntWidgets[EntKeyField] = entry; } { GtkWidget* entry = gtk_entry_new(); gtk_widget_show( entry ); gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 1, 2, (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); gtk_widget_set_events( entry, GDK_KEY_PRESS_MASK ); gtk_signal_connect( GTK_OBJECT( entry ), "key_press_event", GTK_SIGNAL_FUNC( entityentry_keypress ), this ); EntWidgets[EntValueField] = entry; } { GtkWidget* label = gtk_label_new( _( "Value" ) ); gtk_widget_show( label ); gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); } { GtkWidget* label = gtk_label_new( _( "Key" ) ); gtk_widget_show( label ); gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); } } { GtkWidget* hbox = gtk_hbox_new( FALSE, 5 ); gtk_widget_show( hbox ); gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, TRUE, 0 ); { GtkWidget* table = gtk_table_new( 3, 3, TRUE ); gtk_widget_show( table ); gtk_box_pack_start( GTK_BOX( hbox ), table, FALSE, TRUE, 0 ); { GtkWidget* button = gtk_button_new_with_label( _( "360" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"360" ); gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 1, 2, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "45" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"45" ); gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "90" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"90" ); gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 0, 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "135" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"135" ); gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 0, 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "180" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"180" ); gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 1, 2, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "225" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"225" ); gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 2, 3, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "270" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"270" ); gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 2, 3, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "315" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"315" ); gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 2, 3, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( GTK_FILL ), 0, 0 ); } } { GtkWidget* vbox2 = gtk_vbox_new( FALSE, 0 ); gtk_widget_show( vbox2 ); gtk_box_pack_start( GTK_BOX( hbox ), vbox2, TRUE, TRUE, 0 ); { GtkWidget* button = gtk_button_new_with_label( _( "Reset" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( ResetEntity ), NULL ); gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "Up" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"-1" ); gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "Dn" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"-2" ); gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); } } { GtkWidget* vbox2 = gtk_vbox_new( FALSE, 0 ); gtk_widget_show( vbox2 ); gtk_box_pack_start( GTK_BOX( hbox ), vbox2, TRUE, TRUE, 0 ); { GtkWidget* button = gtk_button_new_with_label( _( "Del Key/Pair" ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( DelProp ), NULL ); gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "Sound..." ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( AssignSound ), NULL ); gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); } { GtkWidget* button = gtk_button_new_with_label( _( "Model..." ) ); gtk_widget_show( button ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( AssignModel ), NULL ); gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); } } } } if ( g_pParentWnd->FloatingGroupDialog() ) { { GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN ); gtk_widget_show( scr ); gtk_container_set_border_width( GTK_CONTAINER( scr ), 3 ); { GtkWidget* text = gtk_text_view_new(); gtk_widget_set_size_request( text, 0, -1 ); // allow shrinking gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text ), GTK_WRAP_WORD ); gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE ); gtk_container_add( GTK_CONTAINER( scr ), text ); gtk_widget_show( text ); g_qeglobals_gui.d_edit = text; } { GtkWidget* label = gtk_label_new( _( "Console" ) ); gtk_widget_show( label ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), scr, label ); } } } inspector_mode = W_ENTITY; m_pWidget = dlg; g_signal_connect( G_OBJECT( notebook ), "switch_page", G_CALLBACK( switch_page ), dlg ); } }