2 Copyright (C) 1999-2006 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
24 #include "debugging/debugging.h"
27 #include "iselection.h"
31 #include "ireference.h"
32 #include "ifiletypes.h"
37 #include "ifilesystem.h"
38 #include "namespace.h"
39 #include "moduleobserver.h"
43 #include <gtk/gtkmain.h>
44 #include <gtk/gtkbox.h>
45 #include <gtk/gtkentry.h>
46 #include <gtk/gtklabel.h>
47 #include <gtk/gtktable.h>
48 #include <gtk/gtktreemodel.h>
49 #include <gtk/gtktreeview.h>
50 #include <gtk/gtkliststore.h>
51 #include <gtk/gtkcellrenderertext.h>
54 #include "transformlib.h"
55 #include "selectionlib.h"
56 #include "instancelib.h"
57 #include "traverselib.h"
59 #include "eclasslib.h"
61 #include "stream/textfilestream.h"
63 #include "uniquenames.h"
64 #include "modulesystem/singletonmodule.h"
65 #include "modulesystem/moduleregistry.h"
66 #include "stream/stringstream.h"
67 #include "signal/signal.h"
69 #include "gtkutil/filechooser.h"
73 #include "filetypes.h"
75 #include "entityinspector.h"
78 #include "camwindow.h"
80 #include "mainframe.h"
81 #include "preferences.h"
82 #include "referencecache.h"
96 //globalOutputStream() << "construct " << makeQuoted(c_str()) << "\n";
97 m_names.insert(name_read(c_str()));
104 //globalOutputStream() << "destroy " << makeQuoted(c_str()) << "\n";
105 m_names.erase(name_read(c_str()));
109 NameObserver& operator=(const NameObserver& other);
111 NameObserver(UniqueNames& names) : m_names(names)
115 NameObserver(const NameObserver& other) : m_names(other.m_names), m_name(other.m_name)
125 return string_empty(c_str());
127 const char* c_str() const
129 return m_name.c_str();
131 void nameChanged(const char* name)
137 typedef MemberCaller1<NameObserver, const char*, &NameObserver::nameChanged> NameChangedCaller;
140 class BasicNamespace : public Namespace
142 typedef std::map<NameCallback, NameObserver> Names;
144 UniqueNames m_uniqueNames;
148 ASSERT_MESSAGE(m_names.empty(), "namespace: names still registered at shutdown");
150 void attach(const NameCallback& setName, const NameCallbackCallback& attachObserver)
152 std::pair<Names::iterator, bool> result = m_names.insert(Names::value_type(setName, m_uniqueNames));
153 ASSERT_MESSAGE(result.second, "cannot attach name");
154 attachObserver(NameObserver::NameChangedCaller((*result.first).second));
155 //globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
157 void detach(const NameCallback& setName, const NameCallbackCallback& detachObserver)
159 Names::iterator i = m_names.find(setName);
160 ASSERT_MESSAGE(i != m_names.end(), "cannot detach name");
161 //globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
162 detachObserver(NameObserver::NameChangedCaller((*i).second));
166 void makeUnique(const char* name, const NameCallback& setName) const
169 name_write(buffer, m_uniqueNames.make_unique(name_read(name)));
173 void mergeNames(const BasicNamespace& other) const
175 typedef std::list<NameCallback> SetNameCallbacks;
176 typedef std::map<CopiedString, SetNameCallbacks> NameGroups;
179 UniqueNames uniqueNames(other.m_uniqueNames);
181 for(Names::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
183 groups[(*i).second.c_str()].push_back((*i).first);
186 for(NameGroups::iterator i = groups.begin(); i != groups.end(); ++i)
188 name_t uniqueName(uniqueNames.make_unique(name_read((*i).first.c_str())));
189 uniqueNames.insert(uniqueName);
192 name_write(buffer, uniqueName);
194 //globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
196 SetNameCallbacks& setNameCallbacks = (*i).second;
198 for(SetNameCallbacks::const_iterator j = setNameCallbacks.begin(); j != setNameCallbacks.end(); ++j)
206 BasicNamespace g_defaultNamespace;
207 BasicNamespace g_cloneNamespace;
211 Namespace* m_namespace;
213 typedef Namespace Type;
214 STRING_CONSTANT(Name, "*");
218 m_namespace = &g_defaultNamespace;
220 Namespace* getTable()
226 typedef SingletonModule<NamespaceAPI> NamespaceModule;
227 typedef Static<NamespaceModule> StaticNamespaceModule;
228 StaticRegisterModule staticRegisterDefaultNamespace(StaticNamespaceModule::instance());
231 std::list<Namespaced*> g_cloned;
233 inline Namespaced* Node_getNamespaced(scene::Node& node)
235 return NodeTypeCast<Namespaced>::cast(node);
238 void Node_gatherNamespaced(scene::Node& node)
240 Namespaced* namespaced = Node_getNamespaced(node);
243 g_cloned.push_back(namespaced);
247 class GatherNamespaced : public scene::Traversable::Walker
250 bool pre(scene::Node& node) const
252 Node_gatherNamespaced(node);
257 void Map_gatherNamespaced(scene::Node& root)
259 Node_traverseSubgraph(root, GatherNamespaced());
262 void Map_mergeClonedNames()
264 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
266 (*i)->setNamespace(g_cloneNamespace);
268 g_cloneNamespace.mergeNames(g_defaultNamespace);
269 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
271 (*i)->setNamespace(g_defaultNamespace);
285 void set(scene::Node* node)
293 scene::Node* get() const
300 void Map_SetValid(Map& map, bool valid);
301 void Map_UpdateTitle(const Map& map);
302 void Map_SetWorldspawn(Map& map, scene::Node* node);
305 class Map : public ModuleObserver
309 Resource* m_resource;
313 void (*m_modified_changed)(const Map&);
315 Signal0 m_mapValidCallbacks;
317 WorldNode m_world_node; // "classname" "worldspawn" !
319 Map() : m_resource(0), m_valid(false), m_modified_changed(Map_UpdateTitle)
327 if(Map_Unnamed(*this))
329 g_map.m_resource->setNode(NewMapRoot("").get_pointer());
330 MapFile* map = Node_getMapFile(*g_map.m_resource->getNode());
341 GlobalSceneGraph().insert_root(*m_resource->getNode());
345 Map_SetValid(g_map, true);
352 Map_SetValid(g_map, false);
353 Map_SetWorldspawn(g_map, 0);
356 GlobalUndoSystem().clear();
358 GlobalSceneGraph().erase_root();
364 Map* g_currentMap = 0;
366 void Map_addValidCallback(Map& map, const SignalHandler& handler)
368 map.m_mapValidCallbacks.connectLast(handler);
371 bool Map_Valid(const Map& map)
376 void Map_SetValid(Map& map, bool valid)
379 map.m_mapValidCallbacks();
383 const char* Map_Name(const Map& map)
385 return map.m_name.c_str();
388 bool Map_Unnamed(const Map& map)
390 return string_equal(Map_Name(map), "unnamed.map");
393 inline const MapFormat& MapFormat_forFile(const char* filename)
395 const char* moduleName = findModuleName(GetFileTypeRegistry(), MapFormat::Name(), path_get_extension(filename));
396 MapFormat* format = Radiant_getMapModules().findModule(moduleName);
397 ASSERT_MESSAGE(format != 0, "map format not found for file " << makeQuoted(filename));
401 const MapFormat& Map_getFormat(const Map& map)
403 return MapFormat_forFile(Map_Name(map));
407 bool Map_Modified(const Map& map)
409 return map.m_modified;
412 void Map_SetModified(Map& map, bool modified)
414 if(map.m_modified ^ modified)
416 map.m_modified = modified;
418 map.m_modified_changed(map);
422 void Map_UpdateTitle(const Map& map)
424 Sys_SetTitle(map.m_name.c_str(), Map_Modified(map));
429 scene::Node* Map_GetWorldspawn(const Map& map)
431 return map.m_world_node.get();
434 void Map_SetWorldspawn(Map& map, scene::Node* node)
436 map.m_world_node.set(node);
441 // need that in a variable, will have to tweak depending on the game
442 float g_MaxWorldCoord = 64*1024;
443 float g_MinWorldCoord = -64*1024;
445 void AddRegionBrushes (void);
446 void RemoveRegionBrushes (void);
452 free all map elements, reinitialize the structures that depend on them
459 g_map.m_resource->detach(g_map);
460 GlobalReferenceCache().release(g_map.m_name.c_str());
461 g_map.m_resource = 0;
468 class EntityFindByClassname : public scene::Graph::Walker
473 EntityFindByClassname(const char* name, Entity*& entity) : m_name(name), m_entity(entity)
477 bool pre(const scene::Path& path, scene::Instance& instance) const
481 Entity* entity = Node_getEntity(path.top());
483 && string_equal(m_name, entity->getKeyValue("classname")))
492 Entity* Scene_FindEntityByClass(const char* name)
495 GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
499 Entity *Scene_FindPlayerStart()
501 typedef const char* StaticString;
502 StaticString strings[] = {
504 "info_player_deathmatch",
505 "team_CTF_redplayer",
506 "team_CTF_blueplayer",
508 "team_CTF_bluespawn",
510 typedef const StaticString* StaticStringIterator;
511 for(StaticStringIterator i = strings, end = strings+(sizeof(strings)/sizeof(StaticString)); i != end; ++i)
513 Entity* entity = Scene_FindEntityByClass(*i);
523 // move the view to a start position
527 void FocusViews(const Vector3& point, float angle)
529 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
530 Camera_setOrigin(camwnd, point);
531 Vector3 angles(Camera_getAngles(camwnd));
532 angles[CAMERA_PITCH] = 0;
533 angles[CAMERA_YAW] = angle;
534 Camera_setAngles(camwnd, angles);
536 XYWnd* xywnd = g_pParentWnd->GetXYWnd();
537 xywnd->SetOrigin(point);
540 #include "stringio.h"
542 void Map_StartPosition()
544 Entity* entity = Scene_FindPlayerStart();
549 string_parse_vector3(entity->getKeyValue("origin"), origin);
550 FocusViews(origin, string_read_float(entity->getKeyValue("angle")));
554 FocusViews(g_vector3_identity, 0);
559 inline bool node_is_worldspawn(scene::Node& node)
561 Entity* entity = Node_getEntity(node);
562 return entity != 0 && string_equal(entity->getKeyValue("classname"), "worldspawn");
566 // use first worldspawn
567 class entity_updateworldspawn : public scene::Traversable::Walker
570 bool pre(scene::Node& node) const
572 if(node_is_worldspawn(node))
574 if(Map_GetWorldspawn(g_map) == 0)
576 Map_SetWorldspawn(g_map, &node);
583 scene::Node* Map_FindWorldspawn(Map& map)
585 Map_SetWorldspawn(map, 0);
587 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
589 return Map_GetWorldspawn(map);
593 class CollectAllWalker : public scene::Traversable::Walker
596 UnsortedNodeSet& m_nodes;
598 CollectAllWalker(scene::Node& root, UnsortedNodeSet& nodes) : m_root(root), m_nodes(nodes)
601 bool pre(scene::Node& node) const
603 m_nodes.insert(NodeSmartReference(node));
604 Node_getTraversable(m_root)->erase(node);
609 void Node_insertChildFirst(scene::Node& parent, scene::Node& child)
611 UnsortedNodeSet nodes;
612 Node_getTraversable(parent)->traverse(CollectAllWalker(parent, nodes));
613 Node_getTraversable(parent)->insert(child);
615 for(UnsortedNodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i)
617 Node_getTraversable(parent)->insert((*i));
621 scene::Node& createWorldspawn()
623 NodeSmartReference worldspawn(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("worldspawn", true)));
624 Node_insertChildFirst(GlobalSceneGraph().root(), worldspawn);
628 void Map_UpdateWorldspawn(Map& map)
630 if(Map_FindWorldspawn(map) == 0)
632 Map_SetWorldspawn(map, &createWorldspawn());
636 scene::Node& Map_FindOrInsertWorldspawn(Map& map)
638 Map_UpdateWorldspawn(map);
639 return *Map_GetWorldspawn(map);
643 class MapMergeAll : public scene::Traversable::Walker
645 mutable scene::Path m_path;
647 MapMergeAll(const scene::Path& root)
651 bool pre(scene::Node& node) const
653 Node_getTraversable(m_path.top())->insert(node);
654 m_path.push(makeReference(node));
655 selectPath(m_path, true);
658 void post(scene::Node& node) const
664 class MapMergeEntities : public scene::Traversable::Walker
666 mutable scene::Path m_path;
668 MapMergeEntities(const scene::Path& root)
672 bool pre(scene::Node& node) const
674 if(node_is_worldspawn(node))
676 scene::Node* world_node = Map_FindWorldspawn(g_map);
679 Map_SetWorldspawn(g_map, &node);
680 Node_getTraversable(m_path.top().get())->insert(node);
681 m_path.push(makeReference(node));
682 Node_getTraversable(node)->traverse(SelectChildren(m_path));
686 m_path.push(makeReference(*world_node));
687 Node_getTraversable(node)->traverse(MapMergeAll(m_path));
692 Node_getTraversable(m_path.top())->insert(node);
693 m_path.push(makeReference(node));
694 if(node_is_group(node))
696 Node_getTraversable(node)->traverse(SelectChildren(m_path));
700 selectPath(m_path, true);
705 void post(scene::Node& node) const
711 class BasicContainer : public scene::Node::Symbiot
715 NodeTypeCastTable m_casts;
719 NodeContainedCast<BasicContainer, scene::Traversable>::install(m_casts);
721 NodeTypeCastTable& get()
728 TraversableNodeSet m_traverse;
731 typedef LazyStatic<TypeCasts> StaticTypeCasts;
733 scene::Traversable& get(NullType<scene::Traversable>)
738 BasicContainer() : m_node(this, this, StaticTypeCasts::instance().get())
751 /// Merges the map graph rooted at \p node into the global scene-graph.
752 void MergeMap(scene::Node& node)
754 Node_getTraversable(node)->traverse(MapMergeEntities(scene::Path(makeReference(GlobalSceneGraph().root()))));
756 void Map_ImportSelected(TextInputStream& in, const MapFormat& format)
758 NodeSmartReference node((new BasicContainer)->node());
759 format.readGraph(node, in, GlobalEntityCreator());
760 Map_gatherNamespaced(node);
761 Map_mergeClonedNames();
765 inline scene::Cloneable* Node_getCloneable(scene::Node& node)
767 return NodeTypeCast<scene::Cloneable>::cast(node);
770 inline scene::Node& node_clone(scene::Node& node)
772 scene::Cloneable* cloneable = Node_getCloneable(node);
775 return cloneable->clone();
778 return (new scene::NullNode)->node();
781 class CloneAll : public scene::Traversable::Walker
783 mutable scene::Path m_path;
785 CloneAll(scene::Node& root)
786 : m_path(makeReference(root))
789 bool pre(scene::Node& node) const
796 m_path.push(makeReference(node_clone(node)));
797 m_path.top().get().IncRef();
801 void post(scene::Node& node) const
808 Node_getTraversable(m_path.parent())->insert(m_path.top());
810 m_path.top().get().DecRef();
815 scene::Node& Node_Clone(scene::Node& node)
817 scene::Node& clone = node_clone(node);
818 scene::Traversable* traversable = Node_getTraversable(node);
821 traversable->traverse(CloneAll(clone));
827 typedef std::map<CopiedString, std::size_t> EntityBreakdown;
829 class EntityBreakdownWalker : public scene::Graph::Walker
831 EntityBreakdown& m_entitymap;
833 EntityBreakdownWalker(EntityBreakdown& entitymap)
834 : m_entitymap(entitymap)
837 bool pre(const scene::Path& path, scene::Instance& instance) const
839 Entity* entity = Node_getEntity(path.top());
842 const EntityClass& eclass = entity->getEntityClass();
843 if(m_entitymap.find(eclass.name()) == m_entitymap.end())
845 m_entitymap[eclass.name()] = 1;
847 else ++m_entitymap[eclass.name()];
853 void Scene_EntityBreakdown(EntityBreakdown& entitymap)
855 GlobalSceneGraph().traverse(EntityBreakdownWalker(entitymap));
859 WindowPosition g_posMapInfoWnd(c_default_window_pos);
864 GtkEntry* brushes_entry;
865 GtkEntry* entities_entry;
866 GtkListStore* EntityBreakdownWalker;
868 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Map Info", G_CALLBACK(dialog_delete_callback), &dialog);
870 window_set_position(window, g_posMapInfoWnd);
873 GtkVBox* vbox = create_dialog_vbox(4, 4);
874 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
877 GtkHBox* hbox = create_dialog_hbox(4);
878 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
881 GtkTable* table = create_dialog_table(2, 2, 4, 4);
882 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
885 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
886 gtk_widget_show(GTK_WIDGET(entry));
887 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
888 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
889 (GtkAttachOptions) (0), 0, 0);
890 gtk_entry_set_editable(entry, FALSE);
892 brushes_entry = entry;
895 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
896 gtk_widget_show(GTK_WIDGET(entry));
897 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
898 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
899 (GtkAttachOptions) (0), 0, 0);
900 gtk_entry_set_editable(entry, FALSE);
902 entities_entry = entry;
905 GtkWidget* label = gtk_label_new ("Total Brushes");
906 gtk_widget_show (label);
907 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
908 (GtkAttachOptions) (GTK_FILL),
909 (GtkAttachOptions) (0), 0, 0);
910 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
913 GtkWidget* label = gtk_label_new ("Total Entities");
914 gtk_widget_show (label);
915 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
916 (GtkAttachOptions) (GTK_FILL),
917 (GtkAttachOptions) (0), 0, 0);
918 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
922 GtkVBox* vbox2 = create_dialog_vbox(4);
923 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), FALSE, FALSE, 0);
926 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_ok), &dialog);
927 gtk_box_pack_start(GTK_BOX(vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
932 GtkWidget* label = gtk_label_new ("Entity breakdown");
933 gtk_widget_show (label);
934 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, TRUE, 0);
935 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
938 GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4);
939 gtk_box_pack_start(GTK_BOX (vbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
942 GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
944 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
945 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE);
948 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
949 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, 0);
950 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
951 gtk_tree_view_column_set_sort_column_id(column, 0);
955 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
956 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, 0);
957 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
958 gtk_tree_view_column_set_sort_column_id(column, 1);
961 gtk_widget_show(view);
963 gtk_container_add(GTK_CONTAINER(scr), view);
965 EntityBreakdownWalker = store;
973 EntityBreakdown entitymap;
974 Scene_EntityBreakdown(entitymap);
976 for(EntityBreakdown::iterator i=entitymap.begin(); i != entitymap.end(); ++i)
979 sprintf (tmp, "%u", Unsigned((*i).second));
981 gtk_list_store_append(GTK_LIST_STORE(EntityBreakdownWalker), &iter);
982 gtk_list_store_set(GTK_LIST_STORE(EntityBreakdownWalker), &iter, 0, (*i).first.c_str(), 1, tmp, -1);
986 g_object_unref(G_OBJECT(EntityBreakdownWalker));
989 sprintf (tmp, "%u", Unsigned(g_brushCount.get()));
990 gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp);
991 sprintf (tmp, "%u", Unsigned(g_entityCount.get()));
992 gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp);
994 modal_dialog_show(window, dialog);
997 window_get_position(window, g_posMapInfoWnd);
999 gtk_widget_destroy(GTK_WIDGET(window));
1007 const char* m_message;
1009 ScopeTimer(const char* message)
1010 : m_message(message)
1016 double elapsed_time = m_timer.elapsed_msec() / 1000.f;
1017 globalOutputStream() << m_message << " timer: " << FloatFormat(elapsed_time, 5, 2) << " second(s) elapsed\n";
1027 void Map_LoadFile (const char *filename)
1029 globalOutputStream() << "Loading map from " << filename << "\n";
1030 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1032 g_map.m_name = filename;
1033 Map_UpdateTitle(g_map);
1036 ScopeTimer timer("map load");
1038 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1039 g_map.m_resource->attach(g_map);
1041 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
1044 globalOutputStream() << "--- LoadMapFile ---\n";
1045 globalOutputStream() << g_map.m_name.c_str() << "\n";
1047 globalOutputStream() << Unsigned(g_brushCount.get()) << " primitive\n";
1048 globalOutputStream() << Unsigned(g_entityCount.get()) << " entities\n";
1050 //GlobalEntityCreator().printStatistics();
1053 // move the view to a start position
1055 Map_StartPosition();
1057 g_currentMap = &g_map;
1063 virtual bool excluded(scene::Node& node) const = 0;
1066 class ExcludeWalker : public scene::Traversable::Walker
1068 const scene::Traversable::Walker& m_walker;
1069 const Excluder* m_exclude;
1070 mutable bool m_skip;
1072 ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
1073 : m_walker(walker), m_exclude(&exclude), m_skip(false)
1076 bool pre(scene::Node& node) const
1078 if(m_exclude->excluded(node) || node.isRoot())
1089 void post(scene::Node& node) const
1097 m_walker.post(node);
1102 class AnyInstanceSelected : public scene::Instantiable::Visitor
1106 AnyInstanceSelected(bool& selected) : m_selected(selected)
1110 void visit(scene::Instance& instance) const
1112 Selectable* selectable = Instance_getSelectable(instance);
1114 && selectable->isSelected())
1121 bool Node_instanceSelected(scene::Node& node)
1123 scene::Instantiable* instantiable = Node_getInstantiable(node);
1124 ASSERT_NOTNULL(instantiable);
1126 instantiable->forEachInstance(AnyInstanceSelected(selected));
1130 class SelectedDescendantWalker : public scene::Traversable::Walker
1134 SelectedDescendantWalker(bool& selected) : m_selected(selected)
1139 bool pre(scene::Node& node) const
1146 if(Node_instanceSelected(node))
1155 bool Node_selectedDescendant(scene::Node& node)
1158 Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
1162 class SelectionExcluder : public Excluder
1165 bool excluded(scene::Node& node) const
1167 return !Node_selectedDescendant(node);
1171 class IncludeSelectedWalker : public scene::Traversable::Walker
1173 const scene::Traversable::Walker& m_walker;
1174 mutable std::size_t m_selected;
1175 mutable bool m_skip;
1177 bool selectedParent() const
1179 return m_selected != 0;
1182 IncludeSelectedWalker(const scene::Traversable::Walker& walker)
1183 : m_walker(walker), m_selected(0), m_skip(false)
1186 bool pre(scene::Node& node) const
1189 // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
1190 if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
1192 if(Node_instanceSelected(node))
1205 void post(scene::Node& node) const
1213 if(Node_instanceSelected(node))
1217 m_walker.post(node);
1222 void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
1224 scene::Traversable* traversable = Node_getTraversable(root);
1225 if(traversable != 0)
1228 traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
1230 traversable->traverse(IncludeSelectedWalker(walker));
1235 void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
1237 format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
1240 void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
1242 scene::Traversable* traversable = Node_getTraversable(root);
1243 if(traversable != 0)
1245 traversable->traverse(walker);
1249 class RegionExcluder : public Excluder
1252 bool excluded(scene::Node& node) const
1254 return node.excluded();
1258 void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
1260 scene::Traversable* traversable = Node_getTraversable(root);
1261 if(traversable != 0)
1263 traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
1267 bool Map_SaveRegion(const char *filename)
1271 bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
1273 RemoveRegionBrushes();
1279 void Map_RenameAbsolute(const char* absolute)
1281 Resource* resource = GlobalReferenceCache().capture(absolute);
1282 NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
1283 resource->setNode(clone.get_pointer());
1286 //ScopeTimer timer("clone subgraph");
1287 Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
1290 g_map.m_resource->detach(g_map);
1291 GlobalReferenceCache().release(g_map.m_name.c_str());
1293 g_map.m_resource = resource;
1295 g_map.m_name = absolute;
1296 Map_UpdateTitle(g_map);
1298 g_map.m_resource->attach(g_map);
1301 void Map_Rename(const char* filename)
1303 if(!string_equal(g_map.m_name.c_str(), filename))
1305 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1307 Map_RenameAbsolute(filename);
1309 SceneChangeNotify();
1321 ScopeTimer timer("map save");
1323 return true; // assume success..
1334 //globalOutputStream() << "Map_New\n";
1336 g_map.m_name = "unnamed.map";
1337 Map_UpdateTitle(g_map);
1340 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1341 // ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
1342 g_map.m_resource->attach(g_map);
1344 SceneChangeNotify();
1347 FocusViews(g_vector3_identity, 0);
1349 g_currentMap = &g_map;
1352 extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
1354 void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
1357 \todo we need to make sure that the player start IS inside the region and bail out if it's not
1358 the compiler will refuse to compile a map with a player_start somewhere in empty space..
1359 for now, let's just print an error
1362 Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
1364 for (int i=0 ; i<3 ; i++)
1366 if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
1368 globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
1373 // write the info_playerstart
1375 sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
1376 Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
1377 sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
1378 Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
1382 ===========================================================
1386 ===========================================================
1389 Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
1390 Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
1392 scene::Node* region_sides[6];
1393 scene::Node* region_startpoint = 0;
1398 a regioned map will have temp walls put up at the region boundary
1399 \todo TODO TTimo old implementation of region brushes
1400 we still add them straight in the worldspawn and take them out after the map is saved
1401 with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
1404 void AddRegionBrushes (void)
1410 region_sides[i] = &GlobalBrushCreator().createBrush();
1411 Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(NodeSmartReference(*region_sides[i]));
1414 region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
1416 ConstructRegionBrushes(region_sides, region_mins, region_maxs);
1417 ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
1419 Node_getTraversable(GlobalSceneGraph().root())->insert(NodeSmartReference(*region_startpoint));
1422 void RemoveRegionBrushes (void)
1424 for(std::size_t i=0; i<6; i++)
1426 Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
1428 Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
1431 inline void exclude_node(scene::Node& node, bool exclude)
1434 ? node.enable(scene::Node::eExcluded)
1435 : node.disable(scene::Node::eExcluded);
1438 class ExcludeAllWalker : public scene::Graph::Walker
1442 ExcludeAllWalker(bool exclude)
1443 : m_exclude(exclude)
1446 bool pre(const scene::Path& path, scene::Instance& instance) const
1448 exclude_node(path.top(), m_exclude);
1454 void Scene_Exclude_All(bool exclude)
1456 GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
1459 bool Instance_isSelected(const scene::Instance& instance)
1461 const Selectable* selectable = Instance_getSelectable(instance);
1462 return selectable != 0 && selectable->isSelected();
1465 class ExcludeSelectedWalker : public scene::Graph::Walker
1469 ExcludeSelectedWalker(bool exclude)
1470 : m_exclude(exclude)
1473 bool pre(const scene::Path& path, scene::Instance& instance) const
1475 exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
1480 void Scene_Exclude_Selected(bool exclude)
1482 GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
1485 class ExcludeRegionedWalker : public scene::Graph::Walker
1489 ExcludeRegionedWalker(bool exclude)
1490 : m_exclude(exclude)
1493 bool pre(const scene::Path& path, scene::Instance& instance) const
1499 aabb_intersects_aabb(
1500 instance.worldAABB(),
1501 aabb_for_minmax(region_mins, region_maxs)
1511 void Scene_Exclude_Region(bool exclude)
1513 GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
1520 Other filtering options may still be on
1523 void Map_RegionOff()
1525 region_active = false;
1527 region_maxs[0] = g_MaxWorldCoord - 64;
1528 region_mins[0] = g_MinWorldCoord + 64;
1529 region_maxs[1] = g_MaxWorldCoord - 64;
1530 region_mins[1] = g_MinWorldCoord + 64;
1531 region_maxs[2] = g_MaxWorldCoord - 64;
1532 region_mins[2] = g_MinWorldCoord + 64;
1534 Scene_Exclude_All(false);
1537 void Map_ApplyRegion (void)
1539 region_active = true;
1541 Scene_Exclude_Region(false);
1546 ========================
1547 Map_RegionSelectedBrushes
1548 ========================
1550 void Map_RegionSelectedBrushes (void)
1554 if(GlobalSelectionSystem().countSelected() != 0
1555 && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
1557 region_active = true;
1558 Select_GetBounds (region_mins, region_maxs);
1560 Scene_Exclude_Selected(false);
1562 GlobalSelectionSystem().setSelectedAll(false);
1572 void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
1576 region_mins[0] = x_min;
1577 region_maxs[0] = x_max;
1578 region_mins[1] = y_min;
1579 region_maxs[1] = y_max;
1580 region_mins[2] = g_MinWorldCoord + 64;
1581 region_maxs[2] = g_MaxWorldCoord - 64;
1586 void Map_RegionBounds(const AABB& bounds)
1590 region_mins = vector3_subtracted(bounds.origin, bounds.extents);
1591 region_maxs = vector3_added(bounds.origin, bounds.extents);
1603 void Map_RegionBrush (void)
1605 if(GlobalSelectionSystem().countSelected() != 0)
1607 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
1608 Map_RegionBounds(instance.worldAABB());
1617 bool Map_ImportFile(const char* filename)
1619 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1621 bool success = false;
1623 Resource* resource = GlobalReferenceCache().capture(filename);
1624 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1625 if(resource->load())
1627 NodeSmartReference clone(NewMapRoot(""));
1630 //ScopeTimer timer("clone subgraph");
1631 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1634 Map_gatherNamespaced(clone);
1635 Map_mergeClonedNames();
1639 GlobalReferenceCache().release(filename);
1642 SceneChangeNotify();
1652 bool Map_SaveFile(const char* filename)
1654 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1655 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1663 // Saves selected world brushes and whole entities with partial/full selections
1665 bool Map_SaveSelected(const char* filename)
1667 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1671 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1673 scene::Node& m_parent;
1675 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1678 bool pre(const scene::Path& path, scene::Instance& instance) const
1680 if(path.top().get_pointer() != &m_parent
1681 && Node_isPrimitive(path.top()))
1683 Selectable* selectable = Instance_getSelectable(instance);
1685 && selectable->isSelected()
1693 void post(const scene::Path& path, scene::Instance& instance) const
1695 if(path.top().get_pointer() != &m_parent
1696 && Node_isPrimitive(path.top()))
1698 Selectable* selectable = Instance_getSelectable(instance);
1700 && selectable->isSelected()
1703 scene::Node& parent = path.parent();
1704 if(&parent != &m_parent)
1706 NodeSmartReference node(path.top().get());
1707 Node_getTraversable(parent)->erase(node);
1708 Node_getTraversable(m_parent)->insert(node);
1715 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1717 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1720 class CountSelectedBrushes : public scene::Graph::Walker
1722 std::size_t& m_count;
1723 mutable std::size_t m_depth;
1725 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1729 bool pre(const scene::Path& path, scene::Instance& instance) const
1731 if(++m_depth != 1 && path.top().get().isRoot())
1735 Selectable* selectable = Instance_getSelectable(instance);
1737 && selectable->isSelected()
1738 && Node_isPrimitive(path.top()))
1744 void post(const scene::Path& path, scene::Instance& instance) const
1750 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1753 graph.traverse(CountSelectedBrushes(count));
1765 const char* nodetype_get_name(ENodeType type)
1767 if(type == eNodeMap)
1769 if(type == eNodeEntity)
1771 if(type == eNodePrimitive)
1776 ENodeType node_get_nodetype(scene::Node& node)
1778 if(Node_isEntity(node))
1782 if(Node_isPrimitive(node))
1784 return eNodePrimitive;
1786 return eNodeUnknown;
1789 bool contains_entity(scene::Node& node)
1791 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1794 bool contains_primitive(scene::Node& node)
1796 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1799 ENodeType node_get_contains(scene::Node& node)
1801 if(contains_entity(node))
1805 if(contains_primitive(node))
1807 return eNodePrimitive;
1809 return eNodeUnknown;
1812 void Path_parent(const scene::Path& parent, const scene::Path& child)
1814 ENodeType contains = node_get_contains(parent.top());
1815 ENodeType type = node_get_nodetype(child.top());
1817 if(contains != eNodeUnknown && contains == type)
1819 NodeSmartReference node(child.top().get());
1820 Path_deleteTop(child);
1821 Node_getTraversable(parent.top())->insert(node);
1822 SceneChangeNotify();
1826 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1830 void Scene_parentSelected()
1832 UndoableCommand undo("parentSelected");
1834 if(GlobalSelectionSystem().countSelected() > 1)
1836 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1838 const scene::Path& m_parent;
1840 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1843 void visit(scene::Instance& instance) const
1845 if(&m_parent != &instance.path())
1847 Path_parent(m_parent, instance.path());
1852 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1853 GlobalSelectionSystem().foreachSelected(visitor);
1857 globalOutputStream() << "failed - did not find two selected nodes.\n";
1865 if (ConfirmModified("New Map"))
1873 CopiedString g_mapsPath;
1875 const char* getMapsPath()
1877 return g_mapsPath.c_str();
1880 const char* map_open(const char* title)
1882 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name());
1885 const char* map_save(const char* title)
1887 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name());
1892 if (!ConfirmModified("Open Map"))
1895 const char* filename = map_open("Open Map");
1899 MRU_AddFile(filename);
1902 Map_LoadFile(filename);
1908 const char* filename = map_open("Import Map");
1912 UndoableCommand undo("mapImport");
1913 Map_ImportFile(filename);
1919 const char* filename = map_save("Save Map");
1923 MRU_AddFile(filename);
1924 Map_Rename(filename);
1937 if(Map_Unnamed(g_map))
1941 else if(Map_Modified(g_map))
1949 const char* filename = map_save("Export Selection");
1953 Map_SaveSelected(filename);
1959 const char* filename = map_save("Export Region");
1963 Map_SaveRegion(filename);
1971 SceneChangeNotify();
1977 g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1978 g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(),
1979 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1980 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
1982 SceneChangeNotify();
1988 SceneChangeNotify();
1991 void RegionSelected()
1993 Map_RegionSelectedBrushes();
1994 SceneChangeNotify();
2001 class BrushFindByIndexWalker : public scene::Traversable::Walker
2003 mutable std::size_t m_index;
2004 scene::Path& m_path;
2006 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2007 : m_index(index), m_path(path)
2010 bool pre(scene::Node& node) const
2012 if(Node_isPrimitive(node) && m_index-- == 0)
2014 m_path.push(makeReference(node));
2020 class EntityFindByIndexWalker : public scene::Traversable::Walker
2022 mutable std::size_t m_index;
2023 scene::Path& m_path;
2025 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2026 : m_index(index), m_path(path)
2029 bool pre(scene::Node& node) const
2031 if(Node_isEntity(node) && m_index-- == 0)
2033 m_path.push(makeReference(node));
2039 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2041 path.push(makeReference(GlobalSceneGraph().root()));
2043 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2045 if(path.size() == 2)
2047 scene::Traversable* traversable = Node_getTraversable(path.top());
2048 if(traversable != 0)
2050 traversable->traverse(BrushFindByIndexWalker(brush, path));
2055 inline bool Node_hasChildren(scene::Node& node)
2057 scene::Traversable* traversable = Node_getTraversable(node);
2058 return traversable != 0 && !traversable->empty();
2061 void SelectBrush (int entitynum, int brushnum)
2064 Scene_FindEntityBrush(entitynum, brushnum, path);
2065 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2067 scene::Instance* instance = GlobalSceneGraph().find(path);
2068 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2069 Selectable* selectable = Instance_getSelectable(*instance);
2070 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2071 selectable->setSelected(true);
2072 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2077 class BrushFindIndexWalker : public scene::Graph::Walker
2079 mutable const scene::Node* m_node;
2080 std::size_t& m_count;
2082 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2083 : m_node(&node), m_count(count)
2086 bool pre(const scene::Path& path, scene::Instance& instance) const
2088 if(Node_isPrimitive(path.top()))
2090 if(m_node == path.top().get_pointer())
2103 class EntityFindIndexWalker : public scene::Graph::Walker
2105 mutable const scene::Node* m_node;
2106 std::size_t& m_count;
2108 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2109 : m_node(&node), m_count(count)
2112 bool pre(const scene::Path& path, scene::Instance& instance) const
2114 if(Node_isEntity(path.top()))
2116 if(m_node == path.top().get_pointer())
2129 static void GetSelectionIndex (int *ent, int *brush)
2131 std::size_t count_brush = 0;
2132 std::size_t count_entity = 0;
2133 if(GlobalSelectionSystem().countSelected() != 0)
2135 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2137 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2138 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2140 *brush = int(count_brush);
2141 *ent = int(count_entity);
2150 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2152 GtkAccelGroup* accel = gtk_accel_group_new();
2153 gtk_window_add_accel_group(window, accel);
2156 GtkVBox* vbox = create_dialog_vbox(4, 4);
2157 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2159 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2160 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2162 GtkWidget* label = gtk_label_new ("Entity number");
2163 gtk_widget_show (label);
2164 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2165 (GtkAttachOptions) (0),
2166 (GtkAttachOptions) (0), 0, 0);
2169 GtkWidget* label = gtk_label_new ("Brush number");
2170 gtk_widget_show (label);
2171 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2172 (GtkAttachOptions) (0),
2173 (GtkAttachOptions) (0), 0, 0);
2176 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2177 gtk_widget_show(GTK_WIDGET(entry));
2178 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2179 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2180 (GtkAttachOptions) (0), 0, 0);
2181 gtk_widget_grab_focus(GTK_WIDGET(entry));
2185 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2186 gtk_widget_show(GTK_WIDGET(entry));
2187 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2188 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2189 (GtkAttachOptions) (0), 0, 0);
2195 GtkHBox* hbox = create_dialog_hbox(4);
2196 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2198 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2199 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2200 widget_make_default(GTK_WIDGET(button));
2201 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2204 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2205 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2206 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2211 // Initialize dialog
2215 GetSelectionIndex (&ent, &br);
2216 sprintf (buf, "%i", ent);
2217 gtk_entry_set_text(entity, buf);
2218 sprintf (buf, "%i", br);
2219 gtk_entry_set_text(brush, buf);
2221 if(modal_dialog_show(window, dialog) == eIDOK)
2223 const char *entstr = gtk_entry_get_text(entity);
2224 const char *brushstr = gtk_entry_get_text(brush);
2225 SelectBrush (atoi(entstr), atoi(brushstr));
2228 gtk_widget_destroy(GTK_WIDGET(window));
2231 void Map_constructPreferences(PreferencesPage& page)
2233 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2237 class MapEntityClasses : public ModuleObserver
2239 std::size_t m_unrealised;
2241 MapEntityClasses() : m_unrealised(1)
2246 if(--m_unrealised == 0)
2248 if(g_map.m_resource != 0)
2250 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2251 g_map.m_resource->realise();
2257 if(++m_unrealised == 1)
2259 if(g_map.m_resource != 0)
2261 g_map.m_resource->flush();
2262 g_map.m_resource->unrealise();
2268 MapEntityClasses g_MapEntityClasses;
2271 class MapModuleObserver : public ModuleObserver
2273 std::size_t m_unrealised;
2275 MapModuleObserver() : m_unrealised(1)
2280 if(--m_unrealised == 0)
2282 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2283 StringOutputStream buffer(256);
2284 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2285 Q_mkdir(buffer.c_str());
2286 g_mapsPath = buffer.c_str();
2291 if(++m_unrealised == 1)
2298 MapModuleObserver g_MapModuleObserver;
2300 #include "preferencesystem.h"
2302 CopiedString g_strLastMap;
2303 bool g_bLoadLastMap = false;
2305 void Map_Construct()
2307 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2308 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2309 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2310 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2312 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2313 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2314 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2316 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2318 GlobalEntityClassManager().attach(g_MapEntityClasses);
2319 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2324 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2325 GlobalEntityClassManager().detach(g_MapEntityClasses);