2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 // Floating dialog that contains a notebook with at least Entities and Group tabs
24 // I merged the 2 MS Windows dialogs in a single class
26 // Leonardo Zide (leo@lokigames.com)
32 #include <gdk/gdkkeysyms.h>
33 #include <glib/gi18n.h>
35 #include "groupdialog.h"
37 GtkWidget* EntWidgets[EntLast];
38 GtkListStore* g_entlist_store;
39 GtkListStore* g_entprops_store;
40 int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE
41 qboolean multiple_entities;
42 qboolean disable_spawn_get = false;
43 entity_t *edit_entity;
45 static GdkPixmap *tree_pixmaps[7];
46 static GdkBitmap *tree_masks[7];
52 #define IMG_ENTITYGROUP 4
57 #define MAX_GROUPS 4096
58 #define GROUP_DELIMETER '@'
59 #define GROUPNAME "QER_Group_%i"
62 GroupDlg *g_pGroupDlg = &g_wndGroup;
64 // group_t are loaded / saved through "group_info" entities
65 // they hold epairs for group settings and additionnal access info (tree nodes)
66 group_t *g_pGroups = NULL;
68 // the number of active spawnflags
69 static int spawnflag_count;
70 // table: index, match spawnflag item to the spawnflag index (i.e. which bit)
71 static int spawn_table[MAX_FLAGS];
72 // we change the layout depending on how many spawn flags we need to display
73 // the table is a 4x4 in which we need to put the comment box EntWidgets[EntComment] and the spawn flags..
74 static GtkWidget *LayoutTable;
75 // 0: none of them are hooked
76 // 1: only the text, 2: text and four checks, 3: text and 8 checks
77 static int widget_state = 0;
79 static void entity_check( GtkWidget *widget, gpointer data );
81 // =============================================================================
85 ===============================================================
89 ===============================================================
93 GtkListStore* store = g_entlist_store;
95 gtk_list_store_clear( store );
97 for ( eclass_t* e = eclass ; e ; e = e->next )
100 gtk_list_store_append( store, &iter );
101 gtk_list_store_set( store, &iter, 0, e->name, 1, e, -1 );
107 // Reset the key/value (aka property) listbox and fill it with the
108 // k/v pairs from the entity being edited.
111 void SetKeyValuePairs( bool bClearMD3 ){
112 GtkListStore* store = g_entprops_store;
114 gtk_list_store_clear( store );
116 if ( edit_entity == NULL ) {
117 // if there's no entity, then display no key/values
121 // save current key/val pair around filling epair box
122 // row_select wipes it and sets to first in list
123 Str strKey = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) );
124 Str strVal = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntValueField] ) );
127 // Walk through list and add pairs
128 for ( epair_t* epair = edit_entity->epairs ; epair ; epair = epair->next )
131 gtk_list_store_append( store, &iter );
132 gtk_list_store_set( store, &iter, 0, epair->key, 1, epair->value, -1 );
135 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), strKey.GetBuffer() );
136 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), strVal.GetBuffer() );
138 Sys_UpdateWindows( W_CAMERA | W_XY );
143 // Update the checkboxes to reflect the flag state of the entity
145 void SetSpawnFlags( void ){
148 disable_spawn_get = true;
150 f = atoi( ValueForKey( edit_entity, "spawnflags" ) );
151 for ( i = 0 ; i < spawnflag_count ; i++ )
153 v = !!( f & ( 1 << spawn_table[i] ) );
154 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( EntWidgets[EntCheck1 + i] ), v );
156 // take care of the remaining ones
157 for ( i = spawnflag_count ; i < MAX_FLAGS ; i++ )
159 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( EntWidgets[EntCheck1 + i] ), FALSE );
162 disable_spawn_get = false;
167 // Update the entity flags to reflect the state of the checkboxes
169 // NOTE: this function had a tendency to add "spawnflags" "0" on most entities
170 // if this wants to set spawnflags to zero, remove the key
172 void GetSpawnFlags( void ){
177 for ( i = 0 ; i < spawnflag_count ; i++ )
179 v = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( EntWidgets[EntCheck1 + i] ) );
180 f |= v << spawn_table[i];
184 // remove all "spawnflags" keys
185 if ( multiple_entities ) {
188 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
189 DeleteKey( b->owner, "spawnflags" );
192 DeleteKey( edit_entity, "spawnflags" );
197 sprintf( sz, "%i", f );
198 if ( multiple_entities ) {
201 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
202 SetKeyValue( b->owner, "spawnflags", sz );
205 SetKeyValue( edit_entity, "spawnflags", sz );
211 //#define DBG_UPDATESEL
215 // Update the listbox, checkboxes and k/v pairs to reflect the new selection
216 // iIndex is the index in the list box with the class name, -1 if not found
217 bool UpdateSel( int iIndex, eclass_t *pec ){
221 // syndrom of crappy code, we may get into stack overflowing crap with this function and Gtk
222 // if we play with the list of entity classes
223 // using a static flag to prevent recursion
224 static bool bBlockUpdate = false;
226 if ( bBlockUpdate ) {
227 return FALSE; // NOTE TTimo wtf is the return value for anyway?
231 Sys_FPrintf( SYS_WRN, "UpdateSel\n" );
234 if ( selected_brushes.next == &selected_brushes ) {
235 edit_entity = world_entity;
236 multiple_entities = false;
240 edit_entity = selected_brushes.next->owner;
241 for ( b = selected_brushes.next->next ; b != &selected_brushes ; b = b->next )
243 if ( b->owner != edit_entity ) {
244 multiple_entities = true;
250 if ( iIndex != -1 ) {
252 Sys_FPrintf( SYS_WRN,"Setting focus_row to %d\n", iIndex );
256 GtkTreeView* view = GTK_TREE_VIEW( EntWidgets[EntList] );
257 GtkTreePath* path = gtk_tree_path_new();
258 gtk_tree_path_append_index( path, iIndex );
259 gtk_tree_selection_select_path( gtk_tree_view_get_selection( view ), path );
260 gtk_tree_view_scroll_to_cell( view, path, NULL, FALSE, 0, 0 );
261 gtk_tree_path_free( path );
263 bBlockUpdate = false;
270 // Set up the description
272 GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( EntWidgets[EntComment] ) );
273 gtk_text_buffer_set_text( buffer, pec->comments, -1 );
278 // do a first pass to count the spawn flags, don't touch the widgets, we don't know in what state they are
279 for ( i = 0 ; i < MAX_FLAGS ; i++ )
281 if ( pec->flagnames[i] && pec->flagnames[i][0] != 0 && strcmp( pec->flagnames[i],"-" ) ) {
282 spawn_table[spawnflag_count] = i;
287 // what's new widget state
288 if ( spawnflag_count == 0 ) {
291 else if ( spawnflag_count <= 4 ) {
294 else if ( spawnflag_count <= 8 ) {
297 else if ( spawnflag_count <= 12 ) {
303 widget_state = next_state;
304 static int last_count = 0;
306 // disable all remaining boxes
307 // NOTE: these boxes might not even be on display
308 for ( i = 0; i < last_count; i++ )
310 GtkWidget* widget = EntWidgets[EntCheck1 + i];
311 gtk_label_set_text( GTK_LABEL( GTK_BIN( widget )->child ), " " );
312 gtk_widget_hide( widget );
313 gtk_widget_ref( widget );
314 gtk_container_remove( GTK_CONTAINER( LayoutTable ), widget );
316 last_count = spawnflag_count;
318 for ( i = 0 ; i < spawnflag_count ; i++ )
320 GtkWidget* widget = EntWidgets[EntCheck1 + i];
321 gtk_widget_show( widget );
324 str = pec->flagnames[spawn_table[i]];
327 // gtk_table_attach (GTK_TABLE (LayoutTable), widget, i%4, i%4+1, i/4, i/4+1,
328 gtk_table_attach( GTK_TABLE( LayoutTable ), widget, i % 4, i % 4 + 1, i / 4, i / 4 + 1,
329 (GtkAttachOptions) ( GTK_FILL ),
330 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
331 gtk_widget_unref( widget );
333 gtk_label_set_text( GTK_LABEL( GTK_BIN( widget )->child ), str.GetBuffer() );
343 bool UpdateEntitySel( eclass_t *pec ){
345 Sys_FPrintf( SYS_WRN, "UpdateEntitySel\n" );
348 GtkTreeModel* model = GTK_TREE_MODEL( g_entlist_store );
351 for ( gboolean good = gtk_tree_model_get_iter_first( model, &iter ); good != FALSE; good = gtk_tree_model_iter_next( model, &iter ) )
354 gtk_tree_model_get( model, &iter, 0, &text, -1 );
355 if ( strcmp( text, pec->name ) == 0 ) {
357 Sys_FPrintf( SYS_WRN, "found a match: %d %s\n", i, pec->name );
359 return UpdateSel( i, pec );
364 return UpdateSel( -1, pec );
369 // Creates a new entity based on the currently selected brush and entity type.
372 void CreateEntity( void ){
373 GtkTreeView* view = GTK_TREE_VIEW( EntWidgets[EntList] );
375 // check to make sure we have a brush
376 if ( selected_brushes.next == &selected_brushes ) {
377 gtk_MessageBox( g_pParentWnd->m_pWidget, "You must have a selected brush to create an entity", "info" );
381 // find out what type of entity we are trying to create
384 if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( view ), &model, &iter ) == FALSE ) {
385 gtk_MessageBox( g_pParentWnd->m_pWidget, "You must have a selected class to create an entity", "info" );
390 gtk_tree_model_get( model, &iter, 0, &text, -1 );
391 CreateEntityFromName( text, vec3_origin );
394 if ( selected_brushes.next == &selected_brushes ) {
395 edit_entity = world_entity;
398 edit_entity = selected_brushes.next->owner;
403 Select_Brush( edit_entity->brushes.onext );
404 Sys_UpdateWindows( W_ALL );
414 if ( edit_entity == NULL ) {
418 // Get current selection text
419 const char* key = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) );
420 const char* value = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntValueField] ) );
423 // TTimo: if you change the classname to worldspawn you won't merge back in the structural brushes but create a parasite entity
424 if ( !strcmp( key, "classname" ) && !strcmp( value, "worldspawn" ) ) {
425 gtk_MessageBox( g_pParentWnd->m_pWidget, "Cannot change \"classname\" key back to worldspawn.", NULL, MB_OK );
430 // RR2DO2: we don't want spaces in entity keys
431 if ( strstr( key, " " ) ) {
432 gtk_MessageBox( g_pParentWnd->m_pWidget, "No spaces are allowed in entity keys.", NULL, MB_OK );
436 if ( multiple_entities ) {
439 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
440 SetKeyValue( b->owner, key, value );
443 SetKeyValue( edit_entity, key, value );
446 // refresh the prop listbox
450 #ifdef USEPLUGINENTITIES
451 // if it's a plugin entity, perhaps we need to update some drawing parameters
452 // NOTE: perhaps moving this code to a seperate func would help if we need it in other places
453 // TODO: we need to call some update func in the IPluginEntity in case model name changes etc.
454 // ( for the moment only bounding brush is updated ), see UpdateModelBrush in Ritual's Q3Radiant
455 if ( edit_entity->eclass->nShowFlags & ECLASS_PLUGINENTITY ) {
457 edit_entity->pPlugEnt->GetBounds( mins, maxs );
458 // replace old bounding brush by newly computed one
459 // NOTE: this part is similar to Entity_BuildModelBrush in Ritual's Q3Radiant, it can be
460 // usefull moved into a seperate func
461 brush_t *b,*oldbrush;
462 if ( edit_entity->brushes.onext != &edit_entity->brushes ) {
463 oldbrush = edit_entity->brushes.onext;
465 b = Brush_Create( mins, maxs, &edit_entity->eclass->texdef );
466 Entity_LinkBrush( edit_entity, b );
467 Brush_Build( b, true );
469 Brush_AddToList( edit_entity->brushes.onext, &selected_brushes );
471 Brush_Free( oldbrush );
474 #endif // USEPLUGINENTITIES
483 void DelProp( void ){
484 if ( edit_entity == NULL ) {
488 // Get current selection text
489 const char* key = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) );
491 if ( multiple_entities ) {
494 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
495 DeleteKey( b->owner, key );
498 DeleteKey( edit_entity, key );
501 // refresh the prop listbox
509 if ( edit_entity == NULL ) {
513 if ( multiple_entities ) {
516 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
517 for ( pep = b->owner->epairs; pep; )
519 if ( strcmp( pep->key, "classname" ) != 0 ) {
520 DeleteKey( b->owner, pep->key );
521 pep = b->owner->epairs;
529 for ( pep = edit_entity->epairs; pep; )
531 if ( strcmp( pep->key, "classname" ) != 0 ) {
532 DeleteKey( edit_entity, pep->key );
533 pep = edit_entity->epairs;
541 // refresh the dialog
543 for ( i = EntCheck1; i <= EntCheck16; i++ )
544 gtk_signal_handler_block_by_func( GTK_OBJECT( EntWidgets[i] ), GTK_SIGNAL_FUNC( entity_check ), NULL );
546 for ( i = EntCheck1; i <= EntCheck16; i++ )
547 gtk_signal_handler_unblock_by_func( GTK_OBJECT( EntWidgets[i] ), GTK_SIGNAL_FUNC( entity_check ), NULL );
550 bool GetSelectAllCriteria( CString &strKey, CString &strVal ){
553 if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( GTK_TREE_VIEW( EntWidgets[EntProps] ) ), &model, &iter )
554 && ( inspector_mode == W_ENTITY )
555 && GTK_WIDGET_VISIBLE( g_pGroupDlg->m_pWidget ) ) {
556 strKey = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntKeyField] ) );
557 strVal = gtk_entry_get_text( GTK_ENTRY( EntWidgets[EntValueField] ) );
565 char buffer[NAME_MAX];
567 strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() );
568 strcat( buffer, "sound/" );
570 if ( access( buffer, R_OK ) != 0 ) {
572 strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() );
573 strcat( buffer, "/" );
576 const char *filename = file_dialog( g_pGroupDlg->m_pWidget, TRUE, _( "Open Wav File" ), buffer, "sound" );
577 if ( filename != NULL ) {
578 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), "noise" );
579 char *aux = vfsExtractRelativePath( filename );
586 Sys_FPrintf( SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n" );
590 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), str.GetBuffer() );
596 char buffer[NAME_MAX];
598 strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() );
599 strcat( buffer, "models/" );
601 if ( access( buffer, R_OK ) != 0 ) {
603 strcpy( buffer, g_qeglobals.m_strHomeMaps.GetBuffer() );
604 strcat( buffer, "/" );
607 const char *filename = file_dialog( g_pGroupDlg->m_pWidget, TRUE, _( "Open Model" ), buffer, MODEL_MAJOR );
608 if ( filename != NULL ) {
609 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), "model" );
610 // use VFS to get the correct relative path
611 char *aux = vfsExtractRelativePath( filename );
618 Sys_FPrintf( SYS_WRN, "WARNING: could not extract the relative path, using full path instead\n" );
622 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), str.GetBuffer() );
624 edit_entity->brushes.onext->bModelFailed = false;
633 void SetInspectorMode( int iType ){
634 if ( iType == W_GROUP ) {
635 gtk_MessageBox( g_pParentWnd->m_pWidget, "Brush grouping is not functional yet", NULL, MB_OK | MB_ICONWARNING );
638 if ( !g_pParentWnd->FloatingGroupDialog() &&
639 ( iType == W_TEXTURE || iType == W_CONSOLE ) ) {
643 // Is the caller asking us to cycle to the next window?
645 if ( inspector_mode == W_ENTITY ) {
648 else if ( inspector_mode == W_TEXTURE ) {
651 else if ( inspector_mode == W_CONSOLE ) {
662 // entity is always first in the inspector
663 gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_entity ), "Entities" );
664 gtk_notebook_set_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 0 );
668 g_pParentWnd->GetTexWnd()->FocusEdit();
669 gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_entity ), "Textures" );
670 if ( g_pParentWnd->FloatingGroupDialog() ) {
671 gtk_notebook_set_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 1 );
676 gtk_window_set_title( GTK_WINDOW( g_qeglobals_gui.d_entity ), "Console" );
677 if ( g_pParentWnd->FloatingGroupDialog() ) {
678 gtk_notebook_set_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 2 );
683 if ( g_pParentWnd->FloatingGroupDialog() ) {
684 gtk_notebook_set_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 3 );
687 gtk_notebook_set_page( GTK_NOTEBOOK( g_pGroupDlg->m_pNotebook ), 1 );
696 void Group_Add( entity_t *e ){
698 group_t *g = (group_t*)qmalloc(sizeof(group_t));
699 g->epairs = e->epairs;
703 // create a new group node
704 char *text = ValueForKey(g->epairs, "group");
705 g->itemOwner = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_wndGroup.m_hWorld, NULL, &text, 0,
706 tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP],
707 tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], TRUE, TRUE);
713 group_t* Group_Alloc(char *name)
715 group_t *g = (group_t*)qmalloc(sizeof(group_t));
716 SetKeyValue( g->epairs, "group", name );
720 group_t* Group_ForName(const char * name)
722 group_t *g = g_pGroups;
725 if (strcmp( ValueForKey(g->epairs,"group"), name ) == 0)
732 void Group_AddToItem(brush_t *b, GtkCTreeNode* item)
734 int nImage = IMG_BRUSH;
735 if (!g_qeglobals.m_bBrushPrimitMode)
739 const char *pName = NULL;
740 // const char *pNamed = Brush_GetKeyValue(b, "name");
742 if (!b->owner || (b->owner == world_entity))
746 pName = "Generic Patch";
751 pName = "Generic Brush";
757 pName = b->owner->eclass->name;
758 if (b->owner->eclass->fixedsize)
764 nImage = IMG_ENTITYGROUP;
768 GtkCTreeNode *newItem;
769 int i = (b->patchBrush) ? IMG_PATCH : IMG_BRUSH;
770 newItem = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), item, NULL, (gchar**)&pName, 0,
771 tree_pixmaps[i], tree_masks[i], tree_pixmaps[i],
772 tree_masks[i], TRUE, TRUE);
773 gtk_ctree_node_set_row_data (GTK_CTREE (g_wndGroup.m_pTree), newItem, b);
774 b->itemOwner = newItem;
777 void Group_RemoveBrush( brush_t *b ){
779 if (!g_qeglobals.m_bBrushPrimitMode)
785 gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner);
788 DeleteKey(b->epairs, "group");
792 void Group_AddToWorld(brush_t *b)
794 if (!g_qeglobals.m_bBrushPrimitMode)
798 GtkCTreeNode *parent = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0);
799 Group_AddToItem(b, parent);
802 void Group_AddToProperGroup( brush_t *b ){
804 if (!g_qeglobals.m_bBrushPrimitMode)
809 // NOTE: we do a local copy of the "group" key because it gets erased by Group_RemoveBrush
810 const char *pGroup = Brush_GetKeyValue(b, "group");
811 // remove the entry in the tree if there's one
814 gtk_ctree_remove_node (GTK_CTREE (g_pGroupDlg->m_pTree), b->itemOwner);
821 group_t *g = Group_ForName(pGroup);
823 Group_AddToItem(b, g->itemOwner);
826 Sys_Printf("WARNING: unexpected Group_ForName not found in Group_AddToProperGroup\n");
836 void Group_AddToSelected(brush_t *b)
838 if (!g_qeglobals.m_bBrushPrimitMode)
843 item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), GTK_CLIST (g_pGroupDlg->m_pTree)->focus_row);
846 item = gtk_ctree_node_nth (GTK_CTREE (g_pGroupDlg->m_pTree), 0);
848 Group_AddToItem(b, item);
852 void Group_Save(FILE *f)
854 group_t *g = g_pGroups;
857 fprintf(f,"{\n\"classname\" \"group_info\"\n\"group\" \"%s\"\n}\n", ValueForKey( g->epairs, "group" ));
864 if ( !g_qeglobals.m_bBrushPrimitMode ) {
867 // start by cleaning everything
869 //++timo FIXME: we leak, delete the groups on the way (I don't have time to do it now)
871 Sys_Printf( "TODO: fix leak in Group_Init\n" );
873 group_t *g = g_pGroups;
877 for ( ep = g->epairs ; ep ; ep = enext )
888 char *text = "World";
890 gtk_clist_clear (GTK_CLIST (g_wndGroup.m_pTree));
891 world = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), NULL, NULL, &text, 0,
892 tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], tree_pixmaps[IMG_GROUP],
893 tree_masks[IMG_GROUP], FALSE, TRUE);
895 // walk through all the brushes, remove the itemOwner key and add them back where they belong
897 for ( b = active_brushes.next; b != &active_brushes; b = b->next )
900 Group_AddToProperGroup( b );
902 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
905 Group_AddToProperGroup( b );
909 // scan through world_entity for groups in this map?
910 // we use GROUPNAME "QER_group_%i" to look for existing groups and their naming
911 //++timo FIXME: is this actually needed for anything?
912 void Group_GetListFromWorld(GSList **pArray)
914 if (!g_qeglobals.m_bBrushPrimitMode)
919 if (world_entity == NULL)
925 for (int i =0; i < MAX_GROUPS; i++)
927 sprintf(cBuff, GROUPNAME, i);
928 char *pGroup = ValueForKey(world_entity, cBuff);
929 if (pGroup && strlen(pGroup) > 0)
931 *pArray = g_slist_append (*pArray, g_strdup (pGroup));
940 void Group_RemoveListFromWorld()
942 if (!g_qeglobals.m_bBrushPrimitMode)
946 GSList* array = NULL;
947 Group_GetListFromWorld(&array);
951 DeleteKey(world_entity, (char*)array->data);
952 g_free (array->data);
953 array = g_slist_remove (array, array->data);
957 int CountChar(const char *p, char c)
960 int nLen = strlen(p)-1;
971 // =============================================================================
974 static void eclasslist_selection_changed( GtkTreeSelection* selection, gpointer data ){
976 GtkTreeIter selected;
977 // no world entity, we are not ready yet
978 if ( !world_entity ) {
981 if ( gtk_tree_selection_get_selected( selection, &model, &selected ) ) {
983 gtk_tree_model_get( model, &selected, 1, &eclass, -1 );
984 if ( eclass != NULL ) {
985 GtkTreePath* path = gtk_tree_model_get_path( model, &selected );
986 UpdateSel( gtk_tree_path_get_indices( path )[0], eclass );
987 gtk_tree_path_free( path );
992 static gint eclasslist_button_press( GtkWidget *widget, GdkEventButton *event, gpointer data ){
993 if ( event->type == GDK_2BUTTON_PRESS ) {
1000 static gint eclasslist_keypress( GtkWidget* widget, GdkEventKey* event, gpointer data ){
1001 unsigned int code = gdk_keyval_to_upper( event->keyval );
1003 if ( event->keyval == GDK_Return ) {
1008 // select the entity that starts with the key pressed
1009 if ( code <= 'Z' && code >= 'A' ) {
1010 GtkTreeView* view = GTK_TREE_VIEW( EntWidgets[EntList] );
1011 GtkTreeModel* model;
1013 if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( view ), &model, &iter ) == FALSE
1014 || gtk_tree_model_iter_next( model, &iter ) == FALSE ) {
1015 gtk_tree_model_get_iter_first( model, &iter );
1018 for ( unsigned int count = gtk_tree_model_iter_n_children( model, NULL ); count > 0; --count )
1021 gtk_tree_model_get( model, &iter, 0, &text, -1 );
1023 if ( toupper( text[0] ) == (int)code ) {
1024 GtkTreePath* path = gtk_tree_model_get_path( model, &iter );
1025 gtk_tree_selection_select_path( gtk_tree_view_get_selection( view ), path );
1026 gtk_tree_view_scroll_to_cell( view, path, NULL, FALSE, 0, 0 );
1027 gtk_tree_path_free( path );
1033 if ( gtk_tree_model_iter_next( model, &iter ) == FALSE ) {
1034 gtk_tree_model_get_iter_first( model, &iter );
1044 static void proplist_selection_changed( GtkTreeSelection* selection, gpointer data ){
1045 // find out what type of entity we are trying to create
1046 GtkTreeModel* model;
1048 if ( gtk_tree_selection_get_selected( selection, &model, &iter ) == FALSE ) {
1054 gtk_tree_model_get( model, &iter, 0, &key, 1, &val, -1 );
1056 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntKeyField] ), key );
1057 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), val );
1063 static void entity_check( GtkWidget *widget, gpointer data ){
1064 if ( !disable_spawn_get ) {
1069 static void entitylist_angle( GtkWidget *widget, gpointer data ){
1070 SetKeyValue( edit_entity, "angle", (char*)data );
1074 static gint entityentry_keypress( GtkWidget* widget, GdkEventKey* event, gpointer data ){
1075 if ( event->keyval == GDK_Tab ) {
1076 if ( widget == EntWidgets[EntKeyField] ) {
1077 //gtk_entry_set_text (GTK_ENTRY (EntWidgets[EntValueField]), "");
1078 gtk_window_set_focus( GTK_WINDOW( g_pGroupDlg->m_pWidget ), EntWidgets[EntValueField] );
1081 gtk_window_set_focus( GTK_WINDOW( g_pGroupDlg->m_pWidget ), EntWidgets[EntKeyField] );
1086 else if ( event->keyval == GDK_Return ) {
1087 if ( widget == EntWidgets[EntKeyField] ) {
1088 gtk_entry_set_text( GTK_ENTRY( EntWidgets[EntValueField] ), "" );
1089 gtk_window_set_focus( GTK_WINDOW( g_pGroupDlg->m_pWidget ), EntWidgets[EntValueField] );
1101 // add a new group, put all selected brushes into the group
1102 static void groupdlg_add (GtkWidget *widget, gpointer data)
1104 char* name = DoNameDlg ("New Group");
1108 // create a new group node
1110 item = gtk_ctree_insert_node (GTK_CTREE (g_wndGroup.m_pTree), g_pGroupDlg->m_hWorld, NULL, &name, 0,
1111 tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP],
1112 tree_pixmaps[IMG_GROUP], tree_masks[IMG_GROUP], FALSE, TRUE);
1114 // create a new group
1115 group_t *g = Group_Alloc (name);
1116 g->itemOwner = item;
1117 g->next = g_pGroups;
1120 // now add the selected brushes
1121 // NOTE: it would be much faster to give the group_t for adding
1122 // but Select_AddToGroup is the standard way for all other cases
1123 Select_AddToGroup (name);
1128 static void switch_page( GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer data ){
1130 gtk_label_get( GTK_LABEL( gtk_notebook_get_tab_label( notebook, gtk_notebook_get_nth_page( notebook, page_num ) ) ), &text );
1131 gtk_window_set_title( GTK_WINDOW( data ), text );
1133 gpointer item = g_object_get_data( G_OBJECT( g_pParentWnd->m_pWidget ), "menu_misc_selectentitycolor" );
1135 if ( g_pParentWnd->FloatingGroupDialog() ) {
1138 case 0: inspector_mode = W_ENTITY; break;
1139 case 1: inspector_mode = W_TEXTURE; break;
1140 case 2: inspector_mode = W_CONSOLE; break;
1141 default: inspector_mode = W_GROUP; break;
1146 if ( page_num == 0 ) {
1147 inspector_mode = W_ENTITY;
1150 inspector_mode = W_GROUP;
1154 if ( inspector_mode == W_ENTITY ) {
1155 gtk_widget_set_sensitive( GTK_WIDGET( item ), TRUE );
1158 gtk_widget_set_sensitive( GTK_WIDGET( item ), FALSE );
1162 // =============================================================================
1165 // NOTE: when a key is hit with group window focused, we catch in this handler but it gets propagated to mainframe too
1166 // therefore the message will be intercepted and used as a ID_SELECTION_DESELECT
1167 static gint OnDialogKey( GtkWidget* widget, GdkEventKey* event, gpointer data ){
1169 Sys_Printf( "OnDialogKey\n" );
1171 if ( ( event->keyval == GDK_Escape ) && ( g_pParentWnd->CurrentStyle() != MainFrame::eFloating ) ) {
1172 // toggle off the group view (whatever part of it is currently displayed)
1173 // this used to be done with a g_pParentWnd->OnViewEntity(); but it had bad consequences
1174 // http://fenris.lokigames.com/show_bug.cgi?id=2773
1175 widget_delete_hide( g_qeglobals_gui.d_entity );
1181 GroupDlg::GroupDlg (){
1187 extern void PositionWindowOnPrimaryScreen( window_position_t& position );
1190 void GroupDlg::Create(){
1191 if ( m_pWidget != NULL ) {
1195 GtkWidget* dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
1198 if ( g_PrefsDlg.m_bStartOnPrimMon ) {
1199 PositionWindowOnPrimaryScreen( g_PrefsDlg.mWindowInfo.posEntityWnd );
1202 load_window_pos( dlg, g_PrefsDlg.mWindowInfo.posEntityWnd );
1204 gtk_window_set_title( GTK_WINDOW( dlg ), "Entities" );
1205 gtk_signal_connect( GTK_OBJECT( dlg ), "delete_event", GTK_SIGNAL_FUNC( widget_delete_hide ), NULL );
1207 gtk_signal_connect( GTK_OBJECT( dlg ), "key_press_event", GTK_SIGNAL_FUNC( OnDialogKey ), NULL );
1208 gtk_window_set_transient_for( GTK_WINDOW( dlg ), GTK_WINDOW( g_pParentWnd->m_pWidget ) );
1209 g_qeglobals_gui.d_entity = dlg;
1212 GtkWidget* notebook = gtk_notebook_new();
1213 gtk_widget_show( notebook );
1214 gtk_container_add( GTK_CONTAINER( dlg ), notebook );
1215 gtk_notebook_set_tab_pos( GTK_NOTEBOOK( notebook ), GTK_POS_BOTTOM );
1216 m_pNotebook = notebook;
1219 GtkWidget* vbox = gtk_vbox_new( FALSE, 2 );
1220 gtk_widget_show( vbox );
1221 gtk_container_set_border_width( GTK_CONTAINER( vbox ), 2 );
1224 GtkWidget* label = gtk_label_new( "Entities" );
1225 gtk_widget_show( label );
1226 gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), vbox, label );
1230 GtkWidget* split1 = gtk_vpaned_new();
1231 gtk_box_pack_start( GTK_BOX( vbox ), split1, TRUE, TRUE, 0 );
1232 gtk_widget_show( split1 );
1235 GtkWidget* split2 = gtk_vpaned_new();
1236 gtk_paned_add1( GTK_PANED( split1 ), split2 );
1237 gtk_widget_show( split2 );
1239 g_object_set_data( G_OBJECT( dlg ), "split1", split1 );
1240 g_object_set_data( G_OBJECT( dlg ), "split2", split2 );
1243 GtkWidget* vbox2 = gtk_vbox_new( FALSE, 2 );
1244 gtk_widget_show( vbox2 );
1245 gtk_paned_pack2( GTK_PANED( split1 ), vbox2, FALSE, FALSE );
1248 GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL );
1249 gtk_widget_show( scr );
1250 gtk_paned_add1( GTK_PANED( split2 ), scr );
1251 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
1252 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
1255 GtkListStore* store = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER );
1257 GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) );
1258 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE );
1259 g_signal_connect( G_OBJECT( view ), "button_press_event", G_CALLBACK( eclasslist_button_press ), NULL );
1260 g_signal_connect( G_OBJECT( view ), "key_press_event", G_CALLBACK( eclasslist_keypress ), this );
1263 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
1264 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "Key", renderer, "text", 0, NULL );
1265 gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
1269 GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
1270 g_signal_connect( G_OBJECT( selection ), "changed", G_CALLBACK( eclasslist_selection_changed ), dlg );
1273 gtk_widget_show( view );
1275 gtk_container_add( GTK_CONTAINER( scr ), view );
1277 g_object_unref( G_OBJECT( store ) );
1278 EntWidgets[EntList] = view;
1279 g_entlist_store = store;
1284 GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL );
1285 gtk_widget_show( scr );
1286 gtk_paned_add2( GTK_PANED( split2 ), scr );
1287 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS );
1288 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
1291 GtkWidget* text = gtk_text_view_new();
1292 gtk_widget_set_size_request( text, 0, -1 ); // allow shrinking
1293 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text ), GTK_WRAP_WORD );
1294 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE );
1295 gtk_widget_show( text );
1296 gtk_container_add( GTK_CONTAINER( scr ), text );
1297 EntWidgets[EntComment] = text;
1302 // Spawnflags (4 colums wide max, or window gets too wide.)
1303 LayoutTable = gtk_table_new( 4, 4, FALSE );
1304 gtk_box_pack_start( GTK_BOX( vbox2 ), LayoutTable, FALSE, TRUE, 0 );
1305 gtk_widget_show( LayoutTable );
1307 for ( int i = 0; i < MAX_FLAGS; i++ )
1309 GtkWidget* check = gtk_check_button_new_with_label( "" );
1310 gtk_widget_ref( check );
1311 gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL );
1312 EntWidgets[EntCheck1 + i] = check;
1315 if ( g_pGameDescription->quake2 ) {
1316 GtkWidget *check = gtk_check_button_new_with_label( _( "!Easy" ) );
1317 gtk_widget_show( check );
1318 gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL );
1319 /* gtk_table_attach (GTK_TABLE (table), check, 2, 3, 0, 1,
1320 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1321 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);*/
1322 EntWidgets[EntCheck17] = check;
1324 check = gtk_check_button_new_with_label( _( "!Medium" ) );
1325 gtk_widget_show( check );
1326 gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL );
1327 /* gtk_table_attach (GTK_TABLE (table), check, 2, 3, 1, 2,
1328 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1329 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);*/
1330 EntWidgets[EntCheck18] = check;
1332 check = gtk_check_button_new_with_label( _( "!Hard" ) );
1333 gtk_widget_show( check );
1334 gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL );
1335 /* gtk_table_attach (GTK_TABLE (table), check, 2, 3, 2, 3,
1336 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1337 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);*/
1338 EntWidgets[EntCheck19] = check;
1340 check = gtk_check_button_new_with_label( _( "!DeathMatch" ) );
1341 gtk_widget_show( check );
1342 gtk_signal_connect( GTK_OBJECT( check ), "toggled", GTK_SIGNAL_FUNC( entity_check ), NULL );
1343 /* gtk_table_attach (GTK_TABLE (table), check, 2, 3, 3, 4,
1344 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
1345 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);*/
1346 EntWidgets[EntCheck20] = check;
1351 GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL );
1352 gtk_widget_show( scr );
1353 gtk_box_pack_start( GTK_BOX( vbox2 ), scr, TRUE, TRUE, 0 );
1354 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1355 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
1358 GtkListStore* store = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_STRING );
1360 GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) );
1361 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( view ), FALSE );
1364 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
1365 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "", renderer, "text", 0, NULL );
1366 gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
1370 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
1371 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes( "", renderer, "text", 1, NULL );
1372 gtk_tree_view_append_column( GTK_TREE_VIEW( view ), column );
1376 GtkTreeSelection* selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( view ) );
1377 g_signal_connect( G_OBJECT( selection ), "changed", G_CALLBACK( proplist_selection_changed ), dlg );
1380 gtk_widget_show( view );
1382 gtk_container_add( GTK_CONTAINER( scr ), view );
1384 g_object_unref( G_OBJECT( store ) );
1386 EntWidgets[EntProps] = view;
1387 g_entprops_store = store;
1392 int x = g_PrefsDlg.mWindowInfo.nEntitySplit1;
1394 gtk_paned_set_position( GTK_PANED( split1 ), x );
1396 while ( gtk_events_pending() ) gtk_main_iteration();
1397 x = g_PrefsDlg.mWindowInfo.nEntitySplit2;
1400 gtk_paned_set_position( GTK_PANED( split2 ), x );
1407 GtkWidget* table = gtk_table_new( 2, 2, FALSE );
1408 gtk_widget_show( table );
1409 gtk_box_pack_start( GTK_BOX( vbox ), table, FALSE, TRUE, 0 );
1410 gtk_table_set_row_spacings( GTK_TABLE( table ), 3 );
1411 gtk_table_set_col_spacings( GTK_TABLE( table ), 5 );
1414 GtkWidget* entry = gtk_entry_new();
1415 gtk_widget_show( entry );
1416 gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 0, 1,
1417 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
1418 (GtkAttachOptions) ( 0 ), 0, 0 );
1419 gtk_widget_set_events( entry, GDK_KEY_PRESS_MASK );
1420 gtk_signal_connect( GTK_OBJECT( entry ), "key_press_event",
1421 GTK_SIGNAL_FUNC( entityentry_keypress ), this );
1422 EntWidgets[EntKeyField] = entry;
1426 GtkWidget* entry = gtk_entry_new();
1427 gtk_widget_show( entry );
1428 gtk_table_attach( GTK_TABLE( table ), entry, 1, 2, 1, 2,
1429 (GtkAttachOptions) ( GTK_EXPAND | GTK_FILL ),
1430 (GtkAttachOptions) ( 0 ), 0, 0 );
1431 gtk_widget_set_events( entry, GDK_KEY_PRESS_MASK );
1432 gtk_signal_connect( GTK_OBJECT( entry ), "key_press_event",
1433 GTK_SIGNAL_FUNC( entityentry_keypress ), this );
1434 EntWidgets[EntValueField] = entry;
1438 GtkWidget* label = gtk_label_new( _( "Value" ) );
1439 gtk_widget_show( label );
1440 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2,
1441 (GtkAttachOptions) ( GTK_FILL ),
1442 (GtkAttachOptions) ( 0 ), 0, 0 );
1443 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
1447 GtkWidget* label = gtk_label_new( _( "Key" ) );
1448 gtk_widget_show( label );
1449 gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1,
1450 (GtkAttachOptions) ( GTK_FILL ),
1451 (GtkAttachOptions) ( 0 ), 0, 0 );
1452 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
1457 GtkWidget* hbox = gtk_hbox_new( FALSE, 5 );
1458 gtk_widget_show( hbox );
1459 gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, TRUE, 0 );
1462 GtkWidget* table = gtk_table_new( 3, 3, TRUE );
1463 gtk_widget_show( table );
1464 gtk_box_pack_start( GTK_BOX( hbox ), table, FALSE, TRUE, 0 );
1467 GtkWidget* button = gtk_button_new_with_label( _( "360" ) );
1468 gtk_widget_show( button );
1469 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"360" );
1470 gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 1, 2,
1471 (GtkAttachOptions) ( GTK_FILL ),
1472 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1476 GtkWidget* button = gtk_button_new_with_label( _( "45" ) );
1477 gtk_widget_show( button );
1478 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"45" );
1479 gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 0, 1,
1480 (GtkAttachOptions) ( GTK_FILL ),
1481 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1485 GtkWidget* button = gtk_button_new_with_label( _( "90" ) );
1486 gtk_widget_show( button );
1487 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"90" );
1488 gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 0, 1,
1489 (GtkAttachOptions) ( GTK_FILL ),
1490 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1495 GtkWidget* button = gtk_button_new_with_label( _( "135" ) );
1496 gtk_widget_show( button );
1497 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"135" );
1498 gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 0, 1,
1499 (GtkAttachOptions) ( GTK_FILL ),
1500 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1504 GtkWidget* button = gtk_button_new_with_label( _( "180" ) );
1505 gtk_widget_show( button );
1506 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"180" );
1507 gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 1, 2,
1508 (GtkAttachOptions) ( GTK_FILL ),
1509 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1513 GtkWidget* button = gtk_button_new_with_label( _( "225" ) );
1514 gtk_widget_show( button );
1515 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"225" );
1516 gtk_table_attach( GTK_TABLE( table ), button, 0, 1, 2, 3,
1517 (GtkAttachOptions) ( GTK_FILL ),
1518 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1522 GtkWidget* button = gtk_button_new_with_label( _( "270" ) );
1523 gtk_widget_show( button );
1524 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"270" );
1525 gtk_table_attach( GTK_TABLE( table ), button, 1, 2, 2, 3,
1526 (GtkAttachOptions) ( GTK_FILL ),
1527 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1531 GtkWidget* button = gtk_button_new_with_label( _( "315" ) );
1532 gtk_widget_show( button );
1533 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"315" );
1534 gtk_table_attach( GTK_TABLE( table ), button, 2, 3, 2, 3,
1535 (GtkAttachOptions) ( GTK_FILL ),
1536 (GtkAttachOptions) ( GTK_FILL ), 0, 0 );
1541 GtkWidget* vbox2 = gtk_vbox_new( FALSE, 0 );
1542 gtk_widget_show( vbox2 );
1543 gtk_box_pack_start( GTK_BOX( hbox ), vbox2, TRUE, TRUE, 0 );
1546 GtkWidget* button = gtk_button_new_with_label( _( "Reset" ) );
1547 gtk_widget_show( button );
1548 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( ResetEntity ), NULL );
1549 gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 );
1553 GtkWidget* button = gtk_button_new_with_label( _( "Up" ) );
1554 gtk_widget_show( button );
1555 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"-1" );
1556 gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 );
1560 GtkWidget* button = gtk_button_new_with_label( _( "Dn" ) );
1561 gtk_widget_show( button );
1562 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( entitylist_angle ), (void *)"-2" );
1563 gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 );
1568 GtkWidget* vbox2 = gtk_vbox_new( FALSE, 0 );
1569 gtk_widget_show( vbox2 );
1570 gtk_box_pack_start( GTK_BOX( hbox ), vbox2, TRUE, TRUE, 0 );
1573 GtkWidget* button = gtk_button_new_with_label( _( "Del Key/Pair" ) );
1574 gtk_widget_show( button );
1575 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( DelProp ), NULL );
1576 gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 );
1580 GtkWidget* button = gtk_button_new_with_label( _( "Sound..." ) );
1581 gtk_widget_show( button );
1582 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( AssignSound ), NULL );
1583 gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 );
1587 GtkWidget* button = gtk_button_new_with_label( _( "Model..." ) );
1588 gtk_widget_show( button );
1589 gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( AssignModel ), NULL );
1590 gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 );
1596 if ( g_pParentWnd->FloatingGroupDialog() ) {
1598 GtkWidget* scr = gtk_scrolled_window_new( NULL, NULL );
1599 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scr ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1600 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scr ), GTK_SHADOW_IN );
1601 gtk_widget_show( scr );
1602 gtk_container_set_border_width( GTK_CONTAINER( scr ), 3 );
1605 GtkWidget* text = gtk_text_view_new();
1606 gtk_widget_set_size_request( text, 0, -1 ); // allow shrinking
1607 gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text ), GTK_WRAP_WORD );
1608 gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE );
1609 gtk_container_add( GTK_CONTAINER( scr ), text );
1610 gtk_widget_show( text );
1611 g_qeglobals_gui.d_edit = text;
1615 GtkWidget* label = gtk_label_new( _( "Console" ) );
1616 gtk_widget_show( label );
1617 gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), scr, label );
1623 //++timo NOTE: this part for grouping code, don't remove! (we'll put it back in sometime soon)
1626 vbox = gtk_vbox_new (FALSE, 5);
1627 gtk_widget_show (vbox);
1628 gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
1630 scr = gtk_scrolled_window_new (NULL, NULL);
1631 gtk_widget_show (scr);
1632 gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 0);
1633 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1635 ctree = gtk_ctree_new (1, 0);
1636 gtk_widget_show (ctree);
1637 gtk_container_add (GTK_CONTAINER (scr), ctree);
1638 gtk_clist_column_titles_hide (GTK_CLIST (ctree));
1641 hbox = gtk_hbox_new (FALSE, 5);
1642 gtk_widget_show (hbox);
1643 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
1645 button = gtk_button_new_with_label (_("Add..."));
1646 gtk_widget_show (button);
1647 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (groupdlg_add), NULL);
1648 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1649 gtk_widget_set_usize (button, 60, -2);
1651 button = gtk_button_new_with_label (_("Edit..."));
1652 gtk_widget_show (button);
1653 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1654 gtk_widget_set_usize (button, 60, -2);
1656 button = gtk_button_new_with_label (_("Delete"));
1657 gtk_widget_show (button);
1658 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1659 gtk_widget_set_usize (button, 60, -2);
1661 label = gtk_label_new (_("Groups"));
1662 gtk_widget_show (label);
1663 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label);
1665 inspector_mode = W_ENTITY;
1666 // gtk_window_set_title (GTK_WINDOW (dlg), _("Entities"));
1669 load_pixmap ("grouptree1.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[0], &tree_masks[0]);
1670 load_pixmap ("grouptree2.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[1], &tree_masks[1]);
1671 load_pixmap ("grouptree3.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[2], &tree_masks[2]);
1672 load_pixmap ("grouptree4.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[3], &tree_masks[3]);
1673 load_pixmap ("grouptree5.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[4], &tree_masks[4]);
1674 load_pixmap ("grouptree6.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[5], &tree_masks[5]);
1675 load_pixmap ("grouptree7.bmp", g_pParentWnd->m_pWidget, &tree_pixmaps[6], &tree_masks[6]);
1679 g_signal_connect( G_OBJECT( notebook ), "switch_page", G_CALLBACK( switch_page ), dlg );