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"
86 #include "brushmodule.h"
97 //globalOutputStream() << "construct " << makeQuoted(c_str()) << "\n";
98 m_names.insert(name_read(c_str()));
105 //globalOutputStream() << "destroy " << makeQuoted(c_str()) << "\n";
106 m_names.erase(name_read(c_str()));
110 NameObserver& operator=(const NameObserver& other);
112 NameObserver(UniqueNames& names) : m_names(names)
116 NameObserver(const NameObserver& other) : m_names(other.m_names), m_name(other.m_name)
126 return string_empty(c_str());
128 const char* c_str() const
130 return m_name.c_str();
132 void nameChanged(const char* name)
138 typedef MemberCaller1<NameObserver, const char*, &NameObserver::nameChanged> NameChangedCaller;
141 class BasicNamespace : public Namespace
143 typedef std::map<NameCallback, NameObserver> Names;
145 UniqueNames m_uniqueNames;
149 ASSERT_MESSAGE(m_names.empty(), "namespace: names still registered at shutdown");
151 void attach(const NameCallback& setName, const NameCallbackCallback& attachObserver)
153 std::pair<Names::iterator, bool> result = m_names.insert(Names::value_type(setName, m_uniqueNames));
154 ASSERT_MESSAGE(result.second, "cannot attach name");
155 attachObserver(NameObserver::NameChangedCaller((*result.first).second));
156 //globalOutputStream() << "attach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
158 void detach(const NameCallback& setName, const NameCallbackCallback& detachObserver)
160 Names::iterator i = m_names.find(setName);
161 ASSERT_MESSAGE(i != m_names.end(), "cannot detach name");
162 //globalOutputStream() << "detach: " << reinterpret_cast<const unsigned int&>(setName) << "\n";
163 detachObserver(NameObserver::NameChangedCaller((*i).second));
167 void makeUnique(const char* name, const NameCallback& setName) const
170 name_write(buffer, m_uniqueNames.make_unique(name_read(name)));
174 void mergeNames(const BasicNamespace& other) const
176 typedef std::list<NameCallback> SetNameCallbacks;
177 typedef std::map<CopiedString, SetNameCallbacks> NameGroups;
180 UniqueNames uniqueNames(other.m_uniqueNames);
182 for(Names::const_iterator i = m_names.begin(); i != m_names.end(); ++i)
184 groups[(*i).second.c_str()].push_back((*i).first);
187 for(NameGroups::iterator i = groups.begin(); i != groups.end(); ++i)
189 name_t uniqueName(uniqueNames.make_unique(name_read((*i).first.c_str())));
190 uniqueNames.insert(uniqueName);
193 name_write(buffer, uniqueName);
195 //globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
197 SetNameCallbacks& setNameCallbacks = (*i).second;
199 for(SetNameCallbacks::const_iterator j = setNameCallbacks.begin(); j != setNameCallbacks.end(); ++j)
207 BasicNamespace g_defaultNamespace;
208 BasicNamespace g_cloneNamespace;
212 Namespace* m_namespace;
214 typedef Namespace Type;
215 STRING_CONSTANT(Name, "*");
219 m_namespace = &g_defaultNamespace;
221 Namespace* getTable()
227 typedef SingletonModule<NamespaceAPI> NamespaceModule;
228 typedef Static<NamespaceModule> StaticNamespaceModule;
229 StaticRegisterModule staticRegisterDefaultNamespace(StaticNamespaceModule::instance());
232 std::list<Namespaced*> g_cloned;
234 inline Namespaced* Node_getNamespaced(scene::Node& node)
236 return NodeTypeCast<Namespaced>::cast(node);
239 void Node_gatherNamespaced(scene::Node& node)
241 Namespaced* namespaced = Node_getNamespaced(node);
244 g_cloned.push_back(namespaced);
248 class GatherNamespaced : public scene::Traversable::Walker
251 bool pre(scene::Node& node) const
253 Node_gatherNamespaced(node);
258 void Map_gatherNamespaced(scene::Node& root)
260 Node_traverseSubgraph(root, GatherNamespaced());
263 void Map_mergeClonedNames()
265 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
267 (*i)->setNamespace(g_cloneNamespace);
269 g_cloneNamespace.mergeNames(g_defaultNamespace);
270 for(std::list<Namespaced*>::const_iterator i = g_cloned.begin(); i != g_cloned.end(); ++i)
272 (*i)->setNamespace(g_defaultNamespace);
286 void set(scene::Node* node)
294 scene::Node* get() const
301 void Map_SetValid(Map& map, bool valid);
302 void Map_UpdateTitle(const Map& map);
303 void Map_SetWorldspawn(Map& map, scene::Node* node);
306 class Map : public ModuleObserver
310 Resource* m_resource;
314 void (*m_modified_changed)(const Map&);
316 Signal0 m_mapValidCallbacks;
318 WorldNode m_world_node; // "classname" "worldspawn" !
320 Map() : m_resource(0), m_valid(false), m_modified_changed(Map_UpdateTitle)
328 if(Map_Unnamed(*this))
330 g_map.m_resource->setNode(NewMapRoot("").get_pointer());
331 MapFile* map = Node_getMapFile(*g_map.m_resource->getNode());
342 GlobalSceneGraph().insert_root(*m_resource->getNode());
346 Map_SetValid(g_map, true);
353 Map_SetValid(g_map, false);
354 Map_SetWorldspawn(g_map, 0);
357 GlobalUndoSystem().clear();
359 GlobalSceneGraph().erase_root();
365 Map* g_currentMap = 0;
367 void Map_addValidCallback(Map& map, const SignalHandler& handler)
369 map.m_mapValidCallbacks.connectLast(handler);
372 bool Map_Valid(const Map& map)
377 void Map_SetValid(Map& map, bool valid)
380 map.m_mapValidCallbacks();
384 const char* Map_Name(const Map& map)
386 return map.m_name.c_str();
389 bool Map_Unnamed(const Map& map)
391 return string_equal(Map_Name(map), "unnamed.map");
394 inline const MapFormat& MapFormat_forFile(const char* filename)
396 const char* moduleName = findModuleName(GetFileTypeRegistry(), MapFormat::Name(), path_get_extension(filename));
397 MapFormat* format = Radiant_getMapModules().findModule(moduleName);
398 ASSERT_MESSAGE(format != 0, "map format not found for file " << makeQuoted(filename));
402 const MapFormat& Map_getFormat(const Map& map)
404 return MapFormat_forFile(Map_Name(map));
408 bool Map_Modified(const Map& map)
410 return map.m_modified;
413 void Map_SetModified(Map& map, bool modified)
415 if(map.m_modified ^ modified)
417 map.m_modified = modified;
419 map.m_modified_changed(map);
423 void Map_UpdateTitle(const Map& map)
425 Sys_SetTitle(map.m_name.c_str(), Map_Modified(map));
430 scene::Node* Map_GetWorldspawn(const Map& map)
432 return map.m_world_node.get();
435 void Map_SetWorldspawn(Map& map, scene::Node* node)
437 map.m_world_node.set(node);
442 // need that in a variable, will have to tweak depending on the game
443 float g_MaxWorldCoord = 64*1024;
444 float g_MinWorldCoord = -64*1024;
446 void AddRegionBrushes (void);
447 void RemoveRegionBrushes (void);
453 free all map elements, reinitialize the structures that depend on them
460 g_map.m_resource->detach(g_map);
461 GlobalReferenceCache().release(g_map.m_name.c_str());
462 g_map.m_resource = 0;
467 Brush_unlatchPreferences();
470 class EntityFindByClassname : public scene::Graph::Walker
475 EntityFindByClassname(const char* name, Entity*& entity) : m_name(name), m_entity(entity)
479 bool pre(const scene::Path& path, scene::Instance& instance) const
483 Entity* entity = Node_getEntity(path.top());
485 && string_equal(m_name, entity->getKeyValue("classname")))
494 Entity* Scene_FindEntityByClass(const char* name)
497 GlobalSceneGraph().traverse(EntityFindByClassname(name, entity));
501 Entity *Scene_FindPlayerStart()
503 typedef const char* StaticString;
504 StaticString strings[] = {
506 "info_player_deathmatch",
507 "team_CTF_redplayer",
508 "team_CTF_blueplayer",
510 "team_CTF_bluespawn",
512 typedef const StaticString* StaticStringIterator;
513 for(StaticStringIterator i = strings, end = strings+(sizeof(strings)/sizeof(StaticString)); i != end; ++i)
515 Entity* entity = Scene_FindEntityByClass(*i);
525 // move the view to a start position
529 void FocusViews(const Vector3& point, float angle)
531 CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
532 Camera_setOrigin(camwnd, point);
533 Vector3 angles(Camera_getAngles(camwnd));
534 angles[CAMERA_PITCH] = 0;
535 angles[CAMERA_YAW] = angle;
536 Camera_setAngles(camwnd, angles);
538 XYWnd* xywnd = g_pParentWnd->GetXYWnd();
539 xywnd->SetOrigin(point);
542 #include "stringio.h"
544 void Map_StartPosition()
546 Entity* entity = Scene_FindPlayerStart();
551 string_parse_vector3(entity->getKeyValue("origin"), origin);
552 FocusViews(origin, string_read_float(entity->getKeyValue("angle")));
556 FocusViews(g_vector3_identity, 0);
561 inline bool node_is_worldspawn(scene::Node& node)
563 Entity* entity = Node_getEntity(node);
564 return entity != 0 && string_equal(entity->getKeyValue("classname"), "worldspawn");
568 // use first worldspawn
569 class entity_updateworldspawn : public scene::Traversable::Walker
572 bool pre(scene::Node& node) const
574 if(node_is_worldspawn(node))
576 if(Map_GetWorldspawn(g_map) == 0)
578 Map_SetWorldspawn(g_map, &node);
585 scene::Node* Map_FindWorldspawn(Map& map)
587 Map_SetWorldspawn(map, 0);
589 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
591 return Map_GetWorldspawn(map);
595 class CollectAllWalker : public scene::Traversable::Walker
598 UnsortedNodeSet& m_nodes;
600 CollectAllWalker(scene::Node& root, UnsortedNodeSet& nodes) : m_root(root), m_nodes(nodes)
603 bool pre(scene::Node& node) const
605 m_nodes.insert(NodeSmartReference(node));
606 Node_getTraversable(m_root)->erase(node);
611 void Node_insertChildFirst(scene::Node& parent, scene::Node& child)
613 UnsortedNodeSet nodes;
614 Node_getTraversable(parent)->traverse(CollectAllWalker(parent, nodes));
615 Node_getTraversable(parent)->insert(child);
617 for(UnsortedNodeSet::iterator i = nodes.begin(); i != nodes.end(); ++i)
619 Node_getTraversable(parent)->insert((*i));
623 scene::Node& createWorldspawn()
625 NodeSmartReference worldspawn(GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("worldspawn", true)));
626 Node_insertChildFirst(GlobalSceneGraph().root(), worldspawn);
630 void Map_UpdateWorldspawn(Map& map)
632 if(Map_FindWorldspawn(map) == 0)
634 Map_SetWorldspawn(map, &createWorldspawn());
638 scene::Node& Map_FindOrInsertWorldspawn(Map& map)
640 Map_UpdateWorldspawn(map);
641 return *Map_GetWorldspawn(map);
645 class MapMergeAll : public scene::Traversable::Walker
647 mutable scene::Path m_path;
649 MapMergeAll(const scene::Path& root)
653 bool pre(scene::Node& node) const
655 Node_getTraversable(m_path.top())->insert(node);
656 m_path.push(makeReference(node));
657 selectPath(m_path, true);
660 void post(scene::Node& node) const
666 class MapMergeEntities : public scene::Traversable::Walker
668 mutable scene::Path m_path;
670 MapMergeEntities(const scene::Path& root)
674 bool pre(scene::Node& node) const
676 if(node_is_worldspawn(node))
678 scene::Node* world_node = Map_FindWorldspawn(g_map);
681 Map_SetWorldspawn(g_map, &node);
682 Node_getTraversable(m_path.top().get())->insert(node);
683 m_path.push(makeReference(node));
684 Node_getTraversable(node)->traverse(SelectChildren(m_path));
688 m_path.push(makeReference(*world_node));
689 Node_getTraversable(node)->traverse(MapMergeAll(m_path));
694 Node_getTraversable(m_path.top())->insert(node);
695 m_path.push(makeReference(node));
696 if(node_is_group(node))
698 Node_getTraversable(node)->traverse(SelectChildren(m_path));
702 selectPath(m_path, true);
707 void post(scene::Node& node) const
713 class BasicContainer : public scene::Node::Symbiot
717 NodeTypeCastTable m_casts;
721 NodeContainedCast<BasicContainer, scene::Traversable>::install(m_casts);
723 NodeTypeCastTable& get()
730 TraversableNodeSet m_traverse;
733 typedef LazyStatic<TypeCasts> StaticTypeCasts;
735 scene::Traversable& get(NullType<scene::Traversable>)
740 BasicContainer() : m_node(this, this, StaticTypeCasts::instance().get())
753 /// Merges the map graph rooted at \p node into the global scene-graph.
754 void MergeMap(scene::Node& node)
756 Node_getTraversable(node)->traverse(MapMergeEntities(scene::Path(makeReference(GlobalSceneGraph().root()))));
758 void Map_ImportSelected(TextInputStream& in, const MapFormat& format)
760 NodeSmartReference node((new BasicContainer)->node());
761 format.readGraph(node, in, GlobalEntityCreator());
762 Map_gatherNamespaced(node);
763 Map_mergeClonedNames();
767 inline scene::Cloneable* Node_getCloneable(scene::Node& node)
769 return NodeTypeCast<scene::Cloneable>::cast(node);
772 inline scene::Node& node_clone(scene::Node& node)
774 scene::Cloneable* cloneable = Node_getCloneable(node);
777 return cloneable->clone();
780 return (new scene::NullNode)->node();
783 class CloneAll : public scene::Traversable::Walker
785 mutable scene::Path m_path;
787 CloneAll(scene::Node& root)
788 : m_path(makeReference(root))
791 bool pre(scene::Node& node) const
798 m_path.push(makeReference(node_clone(node)));
799 m_path.top().get().IncRef();
803 void post(scene::Node& node) const
810 Node_getTraversable(m_path.parent())->insert(m_path.top());
812 m_path.top().get().DecRef();
817 scene::Node& Node_Clone(scene::Node& node)
819 scene::Node& clone = node_clone(node);
820 scene::Traversable* traversable = Node_getTraversable(node);
823 traversable->traverse(CloneAll(clone));
829 typedef std::map<CopiedString, std::size_t> EntityBreakdown;
831 class EntityBreakdownWalker : public scene::Graph::Walker
833 EntityBreakdown& m_entitymap;
835 EntityBreakdownWalker(EntityBreakdown& entitymap)
836 : m_entitymap(entitymap)
839 bool pre(const scene::Path& path, scene::Instance& instance) const
841 Entity* entity = Node_getEntity(path.top());
844 const EntityClass& eclass = entity->getEntityClass();
845 if(m_entitymap.find(eclass.name()) == m_entitymap.end())
847 m_entitymap[eclass.name()] = 1;
849 else ++m_entitymap[eclass.name()];
855 void Scene_EntityBreakdown(EntityBreakdown& entitymap)
857 GlobalSceneGraph().traverse(EntityBreakdownWalker(entitymap));
861 WindowPosition g_posMapInfoWnd(c_default_window_pos);
866 GtkEntry* brushes_entry;
867 GtkEntry* entities_entry;
868 GtkListStore* EntityBreakdownWalker;
870 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Map Info", G_CALLBACK(dialog_delete_callback), &dialog);
872 window_set_position(window, g_posMapInfoWnd);
875 GtkVBox* vbox = create_dialog_vbox(4, 4);
876 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
879 GtkHBox* hbox = create_dialog_hbox(4);
880 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), FALSE, TRUE, 0);
883 GtkTable* table = create_dialog_table(2, 2, 4, 4);
884 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(table), TRUE, TRUE, 0);
887 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
888 gtk_widget_show(GTK_WIDGET(entry));
889 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
890 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
891 (GtkAttachOptions) (0), 0, 0);
892 gtk_entry_set_editable(entry, FALSE);
894 brushes_entry = entry;
897 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
898 gtk_widget_show(GTK_WIDGET(entry));
899 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
900 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
901 (GtkAttachOptions) (0), 0, 0);
902 gtk_entry_set_editable(entry, FALSE);
904 entities_entry = entry;
907 GtkWidget* label = gtk_label_new ("Total Brushes");
908 gtk_widget_show (label);
909 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
910 (GtkAttachOptions) (GTK_FILL),
911 (GtkAttachOptions) (0), 0, 0);
912 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
915 GtkWidget* label = gtk_label_new ("Total Entities");
916 gtk_widget_show (label);
917 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
918 (GtkAttachOptions) (GTK_FILL),
919 (GtkAttachOptions) (0), 0, 0);
920 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
924 GtkVBox* vbox2 = create_dialog_vbox(4);
925 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(vbox2), FALSE, FALSE, 0);
928 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_ok), &dialog);
929 gtk_box_pack_start(GTK_BOX(vbox2), GTK_WIDGET(button), FALSE, FALSE, 0);
934 GtkWidget* label = gtk_label_new ("Entity breakdown");
935 gtk_widget_show (label);
936 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, TRUE, 0);
937 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
940 GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4);
941 gtk_box_pack_start(GTK_BOX (vbox), GTK_WIDGET(scr), TRUE, TRUE, 0);
944 GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
946 GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
947 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view), TRUE);
950 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
951 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Entity", renderer, "text", 0, 0);
952 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
953 gtk_tree_view_column_set_sort_column_id(column, 0);
957 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
958 GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("Count", renderer, "text", 1, 0);
959 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
960 gtk_tree_view_column_set_sort_column_id(column, 1);
963 gtk_widget_show(view);
965 gtk_container_add(GTK_CONTAINER(scr), view);
967 EntityBreakdownWalker = store;
975 EntityBreakdown entitymap;
976 Scene_EntityBreakdown(entitymap);
978 for(EntityBreakdown::iterator i=entitymap.begin(); i != entitymap.end(); ++i)
981 sprintf (tmp, "%u", Unsigned((*i).second));
983 gtk_list_store_append(GTK_LIST_STORE(EntityBreakdownWalker), &iter);
984 gtk_list_store_set(GTK_LIST_STORE(EntityBreakdownWalker), &iter, 0, (*i).first.c_str(), 1, tmp, -1);
988 g_object_unref(G_OBJECT(EntityBreakdownWalker));
991 sprintf (tmp, "%u", Unsigned(g_brushCount.get()));
992 gtk_entry_set_text (GTK_ENTRY (brushes_entry), tmp);
993 sprintf (tmp, "%u", Unsigned(g_entityCount.get()));
994 gtk_entry_set_text (GTK_ENTRY (entities_entry), tmp);
996 modal_dialog_show(window, dialog);
999 window_get_position(window, g_posMapInfoWnd);
1001 gtk_widget_destroy(GTK_WIDGET(window));
1009 const char* m_message;
1011 ScopeTimer(const char* message)
1012 : m_message(message)
1018 double elapsed_time = m_timer.elapsed_msec() / 1000.f;
1019 globalOutputStream() << m_message << " timer: " << FloatFormat(elapsed_time, 5, 2) << " second(s) elapsed\n";
1029 void Map_LoadFile (const char *filename)
1031 globalOutputStream() << "Loading map from " << filename << "\n";
1032 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1034 g_map.m_name = filename;
1035 Map_UpdateTitle(g_map);
1038 ScopeTimer timer("map load");
1040 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1041 g_map.m_resource->attach(g_map);
1043 Node_getTraversable(GlobalSceneGraph().root())->traverse(entity_updateworldspawn());
1046 globalOutputStream() << "--- LoadMapFile ---\n";
1047 globalOutputStream() << g_map.m_name.c_str() << "\n";
1049 globalOutputStream() << Unsigned(g_brushCount.get()) << " primitive\n";
1050 globalOutputStream() << Unsigned(g_entityCount.get()) << " entities\n";
1052 //GlobalEntityCreator().printStatistics();
1055 // move the view to a start position
1057 Map_StartPosition();
1059 g_currentMap = &g_map;
1065 virtual bool excluded(scene::Node& node) const = 0;
1068 class ExcludeWalker : public scene::Traversable::Walker
1070 const scene::Traversable::Walker& m_walker;
1071 const Excluder* m_exclude;
1072 mutable bool m_skip;
1074 ExcludeWalker(const scene::Traversable::Walker& walker, const Excluder& exclude)
1075 : m_walker(walker), m_exclude(&exclude), m_skip(false)
1078 bool pre(scene::Node& node) const
1080 if(m_exclude->excluded(node) || node.isRoot())
1091 void post(scene::Node& node) const
1099 m_walker.post(node);
1104 class AnyInstanceSelected : public scene::Instantiable::Visitor
1108 AnyInstanceSelected(bool& selected) : m_selected(selected)
1112 void visit(scene::Instance& instance) const
1114 Selectable* selectable = Instance_getSelectable(instance);
1116 && selectable->isSelected())
1123 bool Node_instanceSelected(scene::Node& node)
1125 scene::Instantiable* instantiable = Node_getInstantiable(node);
1126 ASSERT_NOTNULL(instantiable);
1128 instantiable->forEachInstance(AnyInstanceSelected(selected));
1132 class SelectedDescendantWalker : public scene::Traversable::Walker
1136 SelectedDescendantWalker(bool& selected) : m_selected(selected)
1141 bool pre(scene::Node& node) const
1148 if(Node_instanceSelected(node))
1157 bool Node_selectedDescendant(scene::Node& node)
1160 Node_traverseSubgraph(node, SelectedDescendantWalker(selected));
1164 class SelectionExcluder : public Excluder
1167 bool excluded(scene::Node& node) const
1169 return !Node_selectedDescendant(node);
1173 class IncludeSelectedWalker : public scene::Traversable::Walker
1175 const scene::Traversable::Walker& m_walker;
1176 mutable std::size_t m_selected;
1177 mutable bool m_skip;
1179 bool selectedParent() const
1181 return m_selected != 0;
1184 IncludeSelectedWalker(const scene::Traversable::Walker& walker)
1185 : m_walker(walker), m_selected(0), m_skip(false)
1188 bool pre(scene::Node& node) const
1191 // node is not a 'root' AND ( node is selected OR any child of node is selected OR any parent of node is selected )
1192 if(!node.isRoot() && (Node_selectedDescendant(node) || selectedParent()))
1194 if(Node_instanceSelected(node))
1207 void post(scene::Node& node) const
1215 if(Node_instanceSelected(node))
1219 m_walker.post(node);
1224 void Map_Traverse_Selected(scene::Node& root, const scene::Traversable::Walker& walker)
1226 scene::Traversable* traversable = Node_getTraversable(root);
1227 if(traversable != 0)
1230 traversable->traverse(ExcludeWalker(walker, SelectionExcluder()));
1232 traversable->traverse(IncludeSelectedWalker(walker));
1237 void Map_ExportSelected(TextOutputStream& out, const MapFormat& format)
1239 format.writeGraph(GlobalSceneGraph().root(), Map_Traverse_Selected, out);
1242 void Map_Traverse(scene::Node& root, const scene::Traversable::Walker& walker)
1244 scene::Traversable* traversable = Node_getTraversable(root);
1245 if(traversable != 0)
1247 traversable->traverse(walker);
1251 class RegionExcluder : public Excluder
1254 bool excluded(scene::Node& node) const
1256 return node.excluded();
1260 void Map_Traverse_Region(scene::Node& root, const scene::Traversable::Walker& walker)
1262 scene::Traversable* traversable = Node_getTraversable(root);
1263 if(traversable != 0)
1265 traversable->traverse(ExcludeWalker(walker, RegionExcluder()));
1269 bool Map_SaveRegion(const char *filename)
1273 bool success = MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Region, filename);
1275 RemoveRegionBrushes();
1281 void Map_RenameAbsolute(const char* absolute)
1283 Resource* resource = GlobalReferenceCache().capture(absolute);
1284 NodeSmartReference clone(NewMapRoot(path_make_relative(absolute, GlobalFileSystem().findRoot(absolute))));
1285 resource->setNode(clone.get_pointer());
1288 //ScopeTimer timer("clone subgraph");
1289 Node_getTraversable(GlobalSceneGraph().root())->traverse(CloneAll(clone));
1292 g_map.m_resource->detach(g_map);
1293 GlobalReferenceCache().release(g_map.m_name.c_str());
1295 g_map.m_resource = resource;
1297 g_map.m_name = absolute;
1298 Map_UpdateTitle(g_map);
1300 g_map.m_resource->attach(g_map);
1303 void Map_Rename(const char* filename)
1305 if(!string_equal(g_map.m_name.c_str(), filename))
1307 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1309 Map_RenameAbsolute(filename);
1311 SceneChangeNotify();
1323 ScopeTimer timer("map save");
1325 return true; // assume success..
1336 //globalOutputStream() << "Map_New\n";
1338 g_map.m_name = "unnamed.map";
1339 Map_UpdateTitle(g_map);
1342 g_map.m_resource = GlobalReferenceCache().capture(g_map.m_name.c_str());
1343 // ASSERT_MESSAGE(g_map.m_resource->getNode() == 0, "bleh");
1344 g_map.m_resource->attach(g_map);
1346 SceneChangeNotify();
1349 FocusViews(g_vector3_identity, 0);
1351 g_currentMap = &g_map;
1354 extern void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs);
1356 void ConstructRegionStartpoint(scene::Node* startpoint, const Vector3& region_mins, const Vector3& region_maxs)
1359 \todo we need to make sure that the player start IS inside the region and bail out if it's not
1360 the compiler will refuse to compile a map with a player_start somewhere in empty space..
1361 for now, let's just print an error
1364 Vector3 vOrig(Camera_getOrigin(*g_pParentWnd->GetCamWnd()));
1366 for (int i=0 ; i<3 ; i++)
1368 if (vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i])
1370 globalErrorStream() << "Camera is NOT in the region, it's likely that the region won't compile correctly\n";
1375 // write the info_playerstart
1377 sprintf(sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2]);
1378 Node_getEntity(*startpoint)->setKeyValue("origin", sTmp);
1379 sprintf(sTmp, "%d", (int)Camera_getAngles(*g_pParentWnd->GetCamWnd())[CAMERA_YAW]);
1380 Node_getEntity(*startpoint)->setKeyValue("angle", sTmp);
1384 ===========================================================
1388 ===========================================================
1391 Vector3 region_mins(g_MinWorldCoord, g_MinWorldCoord, g_MinWorldCoord);
1392 Vector3 region_maxs(g_MaxWorldCoord, g_MaxWorldCoord, g_MaxWorldCoord);
1394 scene::Node* region_sides[6];
1395 scene::Node* region_startpoint = 0;
1400 a regioned map will have temp walls put up at the region boundary
1401 \todo TODO TTimo old implementation of region brushes
1402 we still add them straight in the worldspawn and take them out after the map is saved
1403 with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module
1406 void AddRegionBrushes (void)
1412 region_sides[i] = &GlobalBrushCreator().createBrush();
1413 Node_getTraversable(Map_FindOrInsertWorldspawn(g_map))->insert(NodeSmartReference(*region_sides[i]));
1416 region_startpoint = &GlobalEntityCreator().createEntity(GlobalEntityClassManager().findOrInsert("info_player_start", false));
1418 ConstructRegionBrushes(region_sides, region_mins, region_maxs);
1419 ConstructRegionStartpoint(region_startpoint, region_mins, region_maxs);
1421 Node_getTraversable(GlobalSceneGraph().root())->insert(NodeSmartReference(*region_startpoint));
1424 void RemoveRegionBrushes (void)
1426 for(std::size_t i=0; i<6; i++)
1428 Node_getTraversable(*Map_GetWorldspawn(g_map))->erase(*region_sides[i]);
1430 Node_getTraversable(GlobalSceneGraph().root())->erase(*region_startpoint);
1433 inline void exclude_node(scene::Node& node, bool exclude)
1436 ? node.enable(scene::Node::eExcluded)
1437 : node.disable(scene::Node::eExcluded);
1440 class ExcludeAllWalker : public scene::Graph::Walker
1444 ExcludeAllWalker(bool exclude)
1445 : m_exclude(exclude)
1448 bool pre(const scene::Path& path, scene::Instance& instance) const
1450 exclude_node(path.top(), m_exclude);
1456 void Scene_Exclude_All(bool exclude)
1458 GlobalSceneGraph().traverse(ExcludeAllWalker(exclude));
1461 bool Instance_isSelected(const scene::Instance& instance)
1463 const Selectable* selectable = Instance_getSelectable(instance);
1464 return selectable != 0 && selectable->isSelected();
1467 class ExcludeSelectedWalker : public scene::Graph::Walker
1471 ExcludeSelectedWalker(bool exclude)
1472 : m_exclude(exclude)
1475 bool pre(const scene::Path& path, scene::Instance& instance) const
1477 exclude_node(path.top(), (instance.isSelected() || instance.childSelected() || instance.parentSelected()) == m_exclude);
1482 void Scene_Exclude_Selected(bool exclude)
1484 GlobalSceneGraph().traverse(ExcludeSelectedWalker(exclude));
1487 class ExcludeRegionedWalker : public scene::Graph::Walker
1491 ExcludeRegionedWalker(bool exclude)
1492 : m_exclude(exclude)
1495 bool pre(const scene::Path& path, scene::Instance& instance) const
1501 aabb_intersects_aabb(
1502 instance.worldAABB(),
1503 aabb_for_minmax(region_mins, region_maxs)
1513 void Scene_Exclude_Region(bool exclude)
1515 GlobalSceneGraph().traverse(ExcludeRegionedWalker(exclude));
1522 Other filtering options may still be on
1525 void Map_RegionOff()
1527 region_active = false;
1529 region_maxs[0] = g_MaxWorldCoord - 64;
1530 region_mins[0] = g_MinWorldCoord + 64;
1531 region_maxs[1] = g_MaxWorldCoord - 64;
1532 region_mins[1] = g_MinWorldCoord + 64;
1533 region_maxs[2] = g_MaxWorldCoord - 64;
1534 region_mins[2] = g_MinWorldCoord + 64;
1536 Scene_Exclude_All(false);
1539 void Map_ApplyRegion (void)
1541 region_active = true;
1543 Scene_Exclude_Region(false);
1548 ========================
1549 Map_RegionSelectedBrushes
1550 ========================
1552 void Map_RegionSelectedBrushes (void)
1556 if(GlobalSelectionSystem().countSelected() != 0
1557 && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
1559 region_active = true;
1560 Select_GetBounds (region_mins, region_maxs);
1562 Scene_Exclude_Selected(false);
1564 GlobalSelectionSystem().setSelectedAll(false);
1574 void Map_RegionXY(float x_min, float y_min, float x_max, float y_max)
1578 region_mins[0] = x_min;
1579 region_maxs[0] = x_max;
1580 region_mins[1] = y_min;
1581 region_maxs[1] = y_max;
1582 region_mins[2] = g_MinWorldCoord + 64;
1583 region_maxs[2] = g_MaxWorldCoord - 64;
1588 void Map_RegionBounds(const AABB& bounds)
1592 region_mins = vector3_subtracted(bounds.origin, bounds.extents);
1593 region_maxs = vector3_added(bounds.origin, bounds.extents);
1605 void Map_RegionBrush (void)
1607 if(GlobalSelectionSystem().countSelected() != 0)
1609 scene::Instance& instance = GlobalSelectionSystem().ultimateSelected();
1610 Map_RegionBounds(instance.worldAABB());
1619 bool Map_ImportFile(const char* filename)
1621 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
1623 bool success = false;
1625 Resource* resource = GlobalReferenceCache().capture(filename);
1626 resource->refresh(); // avoid loading old version if map has changed on disk since last import
1627 if(resource->load())
1629 NodeSmartReference clone(NewMapRoot(""));
1632 //ScopeTimer timer("clone subgraph");
1633 Node_getTraversable(*resource->getNode())->traverse(CloneAll(clone));
1636 Map_gatherNamespaced(clone);
1637 Map_mergeClonedNames();
1641 GlobalReferenceCache().release(filename);
1644 SceneChangeNotify();
1654 bool Map_SaveFile(const char* filename)
1656 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Saving Map");
1657 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse, filename);
1665 // Saves selected world brushes and whole entities with partial/full selections
1667 bool Map_SaveSelected(const char* filename)
1669 return MapResource_saveFile(MapFormat_forFile(filename), GlobalSceneGraph().root(), Map_Traverse_Selected, filename);
1673 class ParentSelectedBrushesToEntityWalker : public scene::Graph::Walker
1675 scene::Node& m_parent;
1677 ParentSelectedBrushesToEntityWalker(scene::Node& parent) : m_parent(parent)
1680 bool pre(const scene::Path& path, scene::Instance& instance) const
1682 if(path.top().get_pointer() != &m_parent
1683 && Node_isPrimitive(path.top()))
1685 Selectable* selectable = Instance_getSelectable(instance);
1687 && selectable->isSelected()
1695 void post(const scene::Path& path, scene::Instance& instance) const
1697 if(path.top().get_pointer() != &m_parent
1698 && Node_isPrimitive(path.top()))
1700 Selectable* selectable = Instance_getSelectable(instance);
1702 && selectable->isSelected()
1705 scene::Node& parent = path.parent();
1706 if(&parent != &m_parent)
1708 NodeSmartReference node(path.top().get());
1709 Node_getTraversable(parent)->erase(node);
1710 Node_getTraversable(m_parent)->insert(node);
1717 void Scene_parentSelectedBrushesToEntity(scene::Graph& graph, scene::Node& parent)
1719 graph.traverse(ParentSelectedBrushesToEntityWalker(parent));
1722 class CountSelectedBrushes : public scene::Graph::Walker
1724 std::size_t& m_count;
1725 mutable std::size_t m_depth;
1727 CountSelectedBrushes(std::size_t& count) : m_count(count), m_depth(0)
1731 bool pre(const scene::Path& path, scene::Instance& instance) const
1733 if(++m_depth != 1 && path.top().get().isRoot())
1737 Selectable* selectable = Instance_getSelectable(instance);
1739 && selectable->isSelected()
1740 && Node_isPrimitive(path.top()))
1746 void post(const scene::Path& path, scene::Instance& instance) const
1752 std::size_t Scene_countSelectedBrushes(scene::Graph& graph)
1755 graph.traverse(CountSelectedBrushes(count));
1767 const char* nodetype_get_name(ENodeType type)
1769 if(type == eNodeMap)
1771 if(type == eNodeEntity)
1773 if(type == eNodePrimitive)
1778 ENodeType node_get_nodetype(scene::Node& node)
1780 if(Node_isEntity(node))
1784 if(Node_isPrimitive(node))
1786 return eNodePrimitive;
1788 return eNodeUnknown;
1791 bool contains_entity(scene::Node& node)
1793 return Node_getTraversable(node) != 0 && !Node_isBrush(node) && !Node_isPatch(node) && !Node_isEntity(node);
1796 bool contains_primitive(scene::Node& node)
1798 return Node_isEntity(node) && Node_getTraversable(node) != 0 && Node_getEntity(node)->isContainer();
1801 ENodeType node_get_contains(scene::Node& node)
1803 if(contains_entity(node))
1807 if(contains_primitive(node))
1809 return eNodePrimitive;
1811 return eNodeUnknown;
1814 void Path_parent(const scene::Path& parent, const scene::Path& child)
1816 ENodeType contains = node_get_contains(parent.top());
1817 ENodeType type = node_get_nodetype(child.top());
1819 if(contains != eNodeUnknown && contains == type)
1821 NodeSmartReference node(child.top().get());
1822 Path_deleteTop(child);
1823 Node_getTraversable(parent.top())->insert(node);
1824 SceneChangeNotify();
1828 globalErrorStream() << "failed - " << nodetype_get_name(type) << " cannot be parented to " << nodetype_get_name(contains) << " container.\n";
1832 void Scene_parentSelected()
1834 UndoableCommand undo("parentSelected");
1836 if(GlobalSelectionSystem().countSelected() > 1)
1838 class ParentSelectedBrushesToEntityWalker : public SelectionSystem::Visitor
1840 const scene::Path& m_parent;
1842 ParentSelectedBrushesToEntityWalker(const scene::Path& parent) : m_parent(parent)
1845 void visit(scene::Instance& instance) const
1847 if(&m_parent != &instance.path())
1849 Path_parent(m_parent, instance.path());
1854 ParentSelectedBrushesToEntityWalker visitor(GlobalSelectionSystem().ultimateSelected().path());
1855 GlobalSelectionSystem().foreachSelected(visitor);
1859 globalOutputStream() << "failed - did not find two selected nodes.\n";
1867 if (ConfirmModified("New Map"))
1875 CopiedString g_mapsPath;
1877 const char* getMapsPath()
1879 return g_mapsPath.c_str();
1882 const char* map_open(const char* title)
1884 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), TRUE, title, getMapsPath(), MapFormat::Name());
1887 const char* map_save(const char* title)
1889 return file_dialog(GTK_WIDGET(MainFrame_getWindow()), FALSE, title, getMapsPath(), MapFormat::Name());
1894 if (!ConfirmModified("Open Map"))
1897 const char* filename = map_open("Open Map");
1901 MRU_AddFile(filename);
1904 Map_LoadFile(filename);
1910 const char* filename = map_open("Import Map");
1914 UndoableCommand undo("mapImport");
1915 Map_ImportFile(filename);
1921 const char* filename = map_save("Save Map");
1925 MRU_AddFile(filename);
1926 Map_Rename(filename);
1939 if(Map_Unnamed(g_map))
1943 else if(Map_Modified(g_map))
1951 const char* filename = map_save("Export Selection");
1955 Map_SaveSelected(filename);
1961 const char* filename = map_save("Export Region");
1965 Map_SaveRegion(filename);
1973 SceneChangeNotify();
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(),
1981 g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(),
1982 g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale()
1984 SceneChangeNotify();
1990 SceneChangeNotify();
1993 void RegionSelected()
1995 Map_RegionSelectedBrushes();
1996 SceneChangeNotify();
2003 class BrushFindByIndexWalker : public scene::Traversable::Walker
2005 mutable std::size_t m_index;
2006 scene::Path& m_path;
2008 BrushFindByIndexWalker(std::size_t index, scene::Path& path)
2009 : m_index(index), m_path(path)
2012 bool pre(scene::Node& node) const
2014 if(Node_isPrimitive(node) && m_index-- == 0)
2016 m_path.push(makeReference(node));
2022 class EntityFindByIndexWalker : public scene::Traversable::Walker
2024 mutable std::size_t m_index;
2025 scene::Path& m_path;
2027 EntityFindByIndexWalker(std::size_t index, scene::Path& path)
2028 : m_index(index), m_path(path)
2031 bool pre(scene::Node& node) const
2033 if(Node_isEntity(node) && m_index-- == 0)
2035 m_path.push(makeReference(node));
2041 void Scene_FindEntityBrush(std::size_t entity, std::size_t brush, scene::Path& path)
2043 path.push(makeReference(GlobalSceneGraph().root()));
2045 Node_getTraversable(path.top())->traverse(EntityFindByIndexWalker(entity, path));
2047 if(path.size() == 2)
2049 scene::Traversable* traversable = Node_getTraversable(path.top());
2050 if(traversable != 0)
2052 traversable->traverse(BrushFindByIndexWalker(brush, path));
2057 inline bool Node_hasChildren(scene::Node& node)
2059 scene::Traversable* traversable = Node_getTraversable(node);
2060 return traversable != 0 && !traversable->empty();
2063 void SelectBrush (int entitynum, int brushnum)
2066 Scene_FindEntityBrush(entitynum, brushnum, path);
2067 if(path.size() == 3 || (path.size() == 2 && !Node_hasChildren(path.top())))
2069 scene::Instance* instance = GlobalSceneGraph().find(path);
2070 ASSERT_MESSAGE(instance != 0, "SelectBrush: path not found in scenegraph");
2071 Selectable* selectable = Instance_getSelectable(*instance);
2072 ASSERT_MESSAGE(selectable != 0, "SelectBrush: path not selectable");
2073 selectable->setSelected(true);
2074 g_pParentWnd->GetXYWnd()->PositionView(instance->worldAABB().origin);
2079 class BrushFindIndexWalker : public scene::Graph::Walker
2081 mutable const scene::Node* m_node;
2082 std::size_t& m_count;
2084 BrushFindIndexWalker(const scene::Node& node, std::size_t& count)
2085 : m_node(&node), m_count(count)
2088 bool pre(const scene::Path& path, scene::Instance& instance) const
2090 if(Node_isPrimitive(path.top()))
2092 if(m_node == path.top().get_pointer())
2105 class EntityFindIndexWalker : public scene::Graph::Walker
2107 mutable const scene::Node* m_node;
2108 std::size_t& m_count;
2110 EntityFindIndexWalker(const scene::Node& node, std::size_t& count)
2111 : m_node(&node), m_count(count)
2114 bool pre(const scene::Path& path, scene::Instance& instance) const
2116 if(Node_isEntity(path.top()))
2118 if(m_node == path.top().get_pointer())
2131 static void GetSelectionIndex (int *ent, int *brush)
2133 std::size_t count_brush = 0;
2134 std::size_t count_entity = 0;
2135 if(GlobalSelectionSystem().countSelected() != 0)
2137 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
2139 GlobalSceneGraph().traverse(BrushFindIndexWalker(path.top(), count_brush));
2140 GlobalSceneGraph().traverse(EntityFindIndexWalker(path.parent(), count_entity));
2142 *brush = int(count_brush);
2143 *ent = int(count_entity);
2152 GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Find Brush", G_CALLBACK(dialog_delete_callback), &dialog);
2154 GtkAccelGroup* accel = gtk_accel_group_new();
2155 gtk_window_add_accel_group(window, accel);
2158 GtkVBox* vbox = create_dialog_vbox(4, 4);
2159 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
2161 GtkTable* table = create_dialog_table(2, 2, 4, 4);
2162 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(table), TRUE, TRUE, 0);
2164 GtkWidget* label = gtk_label_new ("Entity number");
2165 gtk_widget_show (label);
2166 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
2167 (GtkAttachOptions) (0),
2168 (GtkAttachOptions) (0), 0, 0);
2171 GtkWidget* label = gtk_label_new ("Brush number");
2172 gtk_widget_show (label);
2173 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
2174 (GtkAttachOptions) (0),
2175 (GtkAttachOptions) (0), 0, 0);
2178 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2179 gtk_widget_show(GTK_WIDGET(entry));
2180 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 0, 1,
2181 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2182 (GtkAttachOptions) (0), 0, 0);
2183 gtk_widget_grab_focus(GTK_WIDGET(entry));
2187 GtkEntry* entry = GTK_ENTRY(gtk_entry_new());
2188 gtk_widget_show(GTK_WIDGET(entry));
2189 gtk_table_attach(table, GTK_WIDGET(entry), 1, 2, 1, 2,
2190 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
2191 (GtkAttachOptions) (0), 0, 0);
2197 GtkHBox* hbox = create_dialog_hbox(4);
2198 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox), TRUE, TRUE, 0);
2200 GtkButton* button = create_dialog_button("Find", G_CALLBACK(dialog_button_ok), &dialog);
2201 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2202 widget_make_default(GTK_WIDGET(button));
2203 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Return, (GdkModifierType)0, (GtkAccelFlags)0);
2206 GtkButton* button = create_dialog_button("Close", G_CALLBACK(dialog_button_cancel), &dialog);
2207 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(button), FALSE, FALSE, 0);
2208 gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel, GDK_Escape, (GdkModifierType)0, (GtkAccelFlags)0);
2213 // Initialize dialog
2217 GetSelectionIndex (&ent, &br);
2218 sprintf (buf, "%i", ent);
2219 gtk_entry_set_text(entity, buf);
2220 sprintf (buf, "%i", br);
2221 gtk_entry_set_text(brush, buf);
2223 if(modal_dialog_show(window, dialog) == eIDOK)
2225 const char *entstr = gtk_entry_get_text(entity);
2226 const char *brushstr = gtk_entry_get_text(brush);
2227 SelectBrush (atoi(entstr), atoi(brushstr));
2230 gtk_widget_destroy(GTK_WIDGET(window));
2233 void Map_constructPreferences(PreferencesPage& page)
2235 page.appendCheckBox("", "Load last map on open", g_bLoadLastMap);
2239 class MapEntityClasses : public ModuleObserver
2241 std::size_t m_unrealised;
2243 MapEntityClasses() : m_unrealised(1)
2248 if(--m_unrealised == 0)
2250 if(g_map.m_resource != 0)
2252 ScopeDisableScreenUpdates disableScreenUpdates("Processing...", "Loading Map");
2253 g_map.m_resource->realise();
2259 if(++m_unrealised == 1)
2261 if(g_map.m_resource != 0)
2263 g_map.m_resource->flush();
2264 g_map.m_resource->unrealise();
2270 MapEntityClasses g_MapEntityClasses;
2273 class MapModuleObserver : public ModuleObserver
2275 std::size_t m_unrealised;
2277 MapModuleObserver() : m_unrealised(1)
2282 if(--m_unrealised == 0)
2284 ASSERT_MESSAGE(!string_empty(g_qeglobals.m_userGamePath.c_str()), "maps_directory: user-game-path is empty");
2285 StringOutputStream buffer(256);
2286 buffer << g_qeglobals.m_userGamePath.c_str() << "maps/";
2287 Q_mkdir(buffer.c_str());
2288 g_mapsPath = buffer.c_str();
2293 if(++m_unrealised == 1)
2300 MapModuleObserver g_MapModuleObserver;
2302 #include "preferencesystem.h"
2304 CopiedString g_strLastMap;
2305 bool g_bLoadLastMap = false;
2307 void Map_Construct()
2309 GlobalCommands_insert("RegionOff", FreeCaller<RegionOff>());
2310 GlobalCommands_insert("RegionSetXY", FreeCaller<RegionXY>());
2311 GlobalCommands_insert("RegionSetBrush", FreeCaller<RegionBrush>());
2312 GlobalCommands_insert("RegionSetSelection", FreeCaller<RegionSelected>(), Accelerator('R', (GdkModifierType)(GDK_SHIFT_MASK|GDK_CONTROL_MASK)));
2314 GlobalPreferenceSystem().registerPreference("LastMap", CopiedStringImportStringCaller(g_strLastMap), CopiedStringExportStringCaller(g_strLastMap));
2315 GlobalPreferenceSystem().registerPreference("LoadLastMap", BoolImportStringCaller(g_bLoadLastMap), BoolExportStringCaller(g_bLoadLastMap));
2316 GlobalPreferenceSystem().registerPreference("MapInfoDlg", WindowPositionImportStringCaller(g_posMapInfoWnd), WindowPositionExportStringCaller(g_posMapInfoWnd));
2318 PreferencesDialog_addSettingsPreferences(FreeCaller1<PreferencesPage&, Map_constructPreferences>());
2320 GlobalEntityClassManager().attach(g_MapEntityClasses);
2321 Radiant_attachHomePathsObserver(g_MapModuleObserver);
2326 Radiant_detachHomePathsObserver(g_MapModuleObserver);
2327 GlobalEntityClassManager().detach(g_MapEntityClasses);