Fix MSYS2 issues
[xonotic/netradiant.git] / libs / maplib.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 #if !defined ( INCLUDED_MAPLIB_H )
23 #define INCLUDED_MAPLIB_H
24
25 #include "nameable.h"
26 #include "mapfile.h"
27
28 #include "traverselib.h"
29 #include "transformlib.h"
30 #include "scenelib.h"
31 #include "string/string.h"
32 #include "instancelib.h"
33 #include "selectionlib.h"
34 #include "generic/callback.h"
35
36
37 class NameableString : public Nameable
38 {
39 CopiedString m_name;
40 public:
41 NameableString( const char* name )
42         : m_name( name ){
43 }
44
45 const char* name() const {
46         return m_name.c_str();
47 }
48 void attach( const NameCallback& callback ){
49 }
50 void detach( const NameCallback& callback ){
51 }
52 };
53
54
55 class UndoFileChangeTracker : public UndoTracker, public MapFile
56 {
57 std::size_t m_size;
58 std::size_t m_saved;
59 typedef void ( UndoFileChangeTracker::*Pending )();
60 Pending m_pending;
61 Callback m_changed;
62
63 public:
64 UndoFileChangeTracker() : m_size( 0 ), m_saved( MAPFILE_MAX_CHANGES ), m_pending( 0 ){
65 }
66 void print(){
67         globalOutputStream() << "saved: " << Unsigned( m_saved ) << " size: " << Unsigned( m_size ) << "\n";
68 }
69
70 void push(){
71         ++m_size;
72         m_changed();
73         //print();
74 }
75 void pop(){
76         --m_size;
77         m_changed();
78         //print();
79 }
80 void pushOperation(){
81         if ( m_size < m_saved ) {
82                 // redo queue has been flushed.. it is now impossible to get back to the saved state via undo/redo
83                 m_saved = MAPFILE_MAX_CHANGES;
84         }
85         push();
86 }
87 void clear(){
88         m_size = 0;
89         m_changed();
90         //print();
91 }
92 void begin(){
93         m_pending = Pending( &UndoFileChangeTracker::pushOperation );
94 }
95 void undo(){
96         m_pending = Pending( &UndoFileChangeTracker::pop );
97 }
98 void redo(){
99         m_pending = Pending( &UndoFileChangeTracker::push );
100 }
101
102 void changed(){
103         if ( m_pending != 0 ) {
104                 ( ( *this ).*m_pending )();
105                 m_pending = 0;
106         }
107 }
108
109 void save(){
110         m_saved = m_size;
111         m_changed();
112 }
113 bool saved() const {
114         return m_saved == m_size;
115 }
116
117 void setChangedCallback( const Callback& changed ){
118         m_changed = changed;
119         m_changed();
120 }
121
122 std::size_t changes() const {
123         return m_size;
124 }
125 };
126
127
128 class MapRoot : public scene::Node::Symbiot, public scene::Instantiable, public scene::Traversable::Observer
129 {
130 class TypeCasts
131 {
132 NodeTypeCastTable m_casts;
133 public:
134 TypeCasts(){
135         NodeStaticCast<MapRoot, scene::Instantiable>::install( m_casts );
136         NodeContainedCast<MapRoot, scene::Traversable>::install( m_casts );
137         NodeContainedCast<MapRoot, TransformNode>::install( m_casts );
138         NodeContainedCast<MapRoot, Nameable>::install( m_casts );
139         NodeContainedCast<MapRoot, MapFile>::install( m_casts );
140 }
141 NodeTypeCastTable& get(){
142         return m_casts;
143 }
144 };
145
146 scene::Node m_node;
147 IdentityTransform m_transform;
148 TraversableNodeSet m_traverse;
149 InstanceSet m_instances;
150 typedef SelectableInstance Instance;
151 NameableString m_name;
152 UndoFileChangeTracker m_changeTracker;
153 public:
154 typedef LazyStatic<TypeCasts> StaticTypeCasts;
155
156 scene::Traversable& get( NullType<scene::Traversable>){
157         return m_traverse;
158 }
159 TransformNode& get( NullType<TransformNode>){
160         return m_transform;
161 }
162 Nameable& get( NullType<Nameable>){
163         return m_name;
164 }
165 MapFile& get( NullType<MapFile>){
166         return m_changeTracker;
167 }
168
169 MapRoot( const char* name ) : m_node( this, this, StaticTypeCasts::instance().get() ), m_name( name ){
170         m_node.m_isRoot = true;
171
172         m_traverse.attach( this );
173
174         GlobalUndoSystem().trackerAttach( m_changeTracker );
175 }
176 ~MapRoot(){
177 }
178 void release(){
179         GlobalUndoSystem().trackerDetach( m_changeTracker );
180
181         m_traverse.detach( this );
182         delete this;
183 }
184 scene::Node& node(){
185         return m_node;
186 }
187
188 InstanceCounter m_instanceCounter;
189 void instanceAttach( const scene::Path& path ){
190         if ( ++m_instanceCounter.m_count == 1 ) {
191                 m_traverse.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
192         }
193 }
194 void instanceDetach( const scene::Path& path ){
195         if ( --m_instanceCounter.m_count == 0 ) {
196                 m_traverse.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
197         }
198 }
199
200 void insert( scene::Node& child ){
201         m_instances.insert( child );
202 }
203 void erase( scene::Node& child ){
204         m_instances.erase( child );
205 }
206
207 scene::Node& clone() const {
208         return ( new MapRoot( *this ) )->node();
209 }
210
211 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
212         return new Instance( path, parent );
213 }
214 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
215         m_instances.forEachInstance( visitor );
216 }
217 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
218         m_instances.insert( observer, path, instance );
219         instanceAttach( path );
220 }
221 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
222         instanceDetach( path );
223         return m_instances.erase( observer, path );
224 }
225 };
226
227 inline void MapRoot_construct(){
228 }
229
230 inline void MapRoot_destroy(){
231 }
232
233 inline NodeSmartReference NewMapRoot( const char* name ){
234         return NodeSmartReference( ( new MapRoot( name ) )->node() );
235 }
236
237
238 #endif