9764f4af5a817dfe63f5e522d104c788aa3ef99b
[xonotic/netradiant.git] / radiant / filters.cpp
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 #include "filters.h"
23
24 #include "debugging/debugging.h"
25
26 #include "ifilter.h"
27
28 #include "scenelib.h"
29
30 #include <list>
31 #include <set>
32
33 #include "gtkutil/widget.h"
34 #include "gtkutil/menu.h"
35 #include "gtkmisc.h"
36 #include "mainframe.h"
37 #include "commands.h"
38 #include "preferences.h"
39
40 struct filters_globals_t
41 {
42         std::size_t exclude;
43
44         filters_globals_t() :
45                 exclude( 0 ){
46         }
47 };
48
49 filters_globals_t g_filters_globals;
50
51 inline bool filter_active( int mask ){
52         return ( g_filters_globals.exclude & mask ) > 0;
53 }
54
55 class FilterWrapper
56 {
57 public:
58 FilterWrapper( Filter& filter, int mask ) : m_filter( filter ), m_mask( mask ){
59 }
60 void update(){
61         m_filter.setActive( filter_active( m_mask ) );
62 }
63 private:
64 Filter& m_filter;
65 int m_mask;
66 };
67
68 typedef std::list<FilterWrapper> Filters;
69 Filters g_filters;
70
71 typedef std::set<Filterable*> Filterables;
72 Filterables g_filterables;
73
74 void UpdateFilters(){
75         {
76                 for ( Filters::iterator i = g_filters.begin(); i != g_filters.end(); ++i )
77                 {
78                         ( *i ).update();
79                 }
80         }
81
82         {
83                 for ( Filterables::iterator i = g_filterables.begin(); i != g_filterables.end(); ++i )
84                 {
85                         ( *i )->updateFiltered();
86                 }
87         }
88 }
89
90
91 class BasicFilterSystem : public FilterSystem
92 {
93 public:
94 void addFilter( Filter& filter, int mask ){
95         g_filters.push_back( FilterWrapper( filter, mask ) );
96         g_filters.back().update();
97 }
98 void registerFilterable( Filterable& filterable ){
99         ASSERT_MESSAGE( g_filterables.find( &filterable ) == g_filterables.end(), "filterable already registered" );
100         filterable.updateFiltered();
101         g_filterables.insert( &filterable );
102 }
103 void unregisterFilterable( Filterable& filterable ){
104         ASSERT_MESSAGE( g_filterables.find( &filterable ) != g_filterables.end(), "filterable not registered" );
105         g_filterables.erase( &filterable );
106 }
107 };
108
109 BasicFilterSystem g_FilterSystem;
110
111 FilterSystem& GetFilterSystem(){
112         return g_FilterSystem;
113 }
114
115 void PerformFiltering(){
116         UpdateFilters();
117         SceneChangeNotify();
118 }
119
120 class ToggleFilterFlag
121 {
122 const unsigned int m_mask;
123 public:
124 ToggleItem m_item;
125
126 ToggleFilterFlag( unsigned int mask ) : m_mask( mask ), m_item( ActiveCaller( *this ) ){
127 }
128 ToggleFilterFlag( const ToggleFilterFlag& other ) : m_mask( other.m_mask ), m_item( ActiveCaller( *this ) ){
129 }
130 void active( const ImportExportCallback<bool>::Import_t& importCallback ){
131         importCallback( ( g_filters_globals.exclude & m_mask ) != 0 );
132 }
133 typedef MemberCaller<ToggleFilterFlag, void(const ImportExportCallback<bool>::Import_t&), &ToggleFilterFlag::active> ActiveCaller;
134 void toggle(){
135         g_filters_globals.exclude ^= m_mask;
136         m_item.update();
137         PerformFiltering();
138 }
139 void reset(){
140         g_filters_globals.exclude = 0;
141         m_item.update();
142         PerformFiltering();
143 }
144 typedef MemberCaller<ToggleFilterFlag, void(), &ToggleFilterFlag::toggle> ToggleCaller;
145 };
146
147
148 typedef std::list<ToggleFilterFlag> ToggleFilterFlags;
149 ToggleFilterFlags g_filter_items;
150
151 void add_filter_command( unsigned int flag, const char* command, const Accelerator& accelerator ){
152         g_filter_items.push_back( ToggleFilterFlag( flag ) );
153         GlobalToggles_insert( command, ToggleFilterFlag::ToggleCaller( g_filter_items.back() ), ToggleItem::AddCallbackCaller( g_filter_items.back().m_item ), accelerator );
154 }
155
156 void InvertFilters(){
157         std::list<ToggleFilterFlag>::iterator iter;
158
159         for ( iter = g_filter_items.begin(); iter != g_filter_items.end(); ++iter )
160         {
161                 iter->toggle();
162         }
163 }
164
165 void ResetFilters(){
166         std::list<ToggleFilterFlag>::iterator iter;
167
168         for ( iter = g_filter_items.begin(); iter != g_filter_items.end(); ++iter )
169         {
170                 iter->reset();
171         }
172 }
173
174 void Filters_constructMenu( ui::Menu menu_in_menu ){
175         create_check_menu_item_with_mnemonic( menu_in_menu, "World", "FilterWorldBrushes" );
176         create_check_menu_item_with_mnemonic( menu_in_menu, "Entities", "FilterEntities" );
177         if ( g_pGameDescription->mGameType == "doom3" ) {
178                 create_check_menu_item_with_mnemonic( menu_in_menu, "Visportals", "FilterVisportals" );
179         }
180         else
181         {
182                 create_check_menu_item_with_mnemonic( menu_in_menu, "Areaportals", "FilterAreaportals" );
183         }
184         create_check_menu_item_with_mnemonic( menu_in_menu, "Translucent", "FilterTranslucent" );
185         if ( g_pGameDescription->mGameType != "doom3" ) {
186                 create_check_menu_item_with_mnemonic( menu_in_menu, "Liquids", "FilterLiquids" );
187         }
188         create_check_menu_item_with_mnemonic( menu_in_menu, "Caulk", "FilterCaulk" );
189         create_check_menu_item_with_mnemonic( menu_in_menu, "Clips", "FilterClips" );
190         create_check_menu_item_with_mnemonic( menu_in_menu, "Paths", "FilterPaths" );
191         if ( g_pGameDescription->mGameType != "doom3" ) {
192                 create_check_menu_item_with_mnemonic( menu_in_menu, "Clusterportals", "FilterClusterportals" );
193         }
194         create_check_menu_item_with_mnemonic( menu_in_menu, "Lights", "FilterLights" );
195         create_check_menu_item_with_mnemonic( menu_in_menu, "Structural", "FilterStructural" );
196         if ( g_pGameDescription->mGameType != "doom3" ) {
197                 create_check_menu_item_with_mnemonic( menu_in_menu, "Lightgrid", "FilterLightgrid" );
198         }
199         create_check_menu_item_with_mnemonic( menu_in_menu, "Patches", "FilterPatches" );
200         create_check_menu_item_with_mnemonic( menu_in_menu, "Details", "FilterDetails" );
201         create_check_menu_item_with_mnemonic( menu_in_menu, "Hints", "FilterHintsSkips" );
202         create_check_menu_item_with_mnemonic( menu_in_menu, "Models", "FilterModels" );
203         create_check_menu_item_with_mnemonic( menu_in_menu, "Triggers", "FilterTriggers" );
204         if ( g_pGameDescription->mGameType != "doom3" ) {
205                 create_check_menu_item_with_mnemonic( menu_in_menu, "Botclips", "FilterBotClips" );
206                 create_check_menu_item_with_mnemonic( menu_in_menu, "Decals", "FilterDecals" );
207         }
208         // filter manipulation
209         menu_separator( menu_in_menu );
210         create_menu_item_with_mnemonic( menu_in_menu, "Invert filters", "InvertFilters" );
211         create_menu_item_with_mnemonic( menu_in_menu, "Reset filters", "ResetFilters" );
212 }
213
214
215 #include "preferencesystem.h"
216 #include "stringio.h"
217
218 void ConstructFilters(){
219         GlobalPreferenceSystem().registerPreference( "SI_Exclude", SizeImportStringCaller( g_filters_globals.exclude ), SizeExportStringCaller( g_filters_globals.exclude ) );
220
221         GlobalCommands_insert( "InvertFilters", makeCallbackF(InvertFilters) );
222         GlobalCommands_insert( "ResetFilters", makeCallbackF(ResetFilters) );
223
224         add_filter_command( EXCLUDE_WORLD, "FilterWorldBrushes", Accelerator( '1', (GdkModifierType)GDK_MOD1_MASK ) );
225         add_filter_command( EXCLUDE_ENT, "FilterEntities", Accelerator( '2', (GdkModifierType)GDK_MOD1_MASK ) );
226         if ( g_pGameDescription->mGameType == "doom3" ) {
227                 add_filter_command( EXCLUDE_VISPORTALS, "FilterVisportals", Accelerator( '3', (GdkModifierType)GDK_MOD1_MASK ) );
228         }
229         else
230         {
231                 add_filter_command( EXCLUDE_AREAPORTALS, "FilterAreaportals", Accelerator( '3', (GdkModifierType)GDK_MOD1_MASK ) );
232         }
233         add_filter_command( EXCLUDE_TRANSLUCENT, "FilterTranslucent", Accelerator( '4', (GdkModifierType)GDK_MOD1_MASK ) );
234         add_filter_command( EXCLUDE_LIQUIDS, "FilterLiquids", Accelerator( '5', (GdkModifierType)GDK_MOD1_MASK ) );
235         add_filter_command( EXCLUDE_CAULK, "FilterCaulk", Accelerator( '6', (GdkModifierType)GDK_MOD1_MASK ) );
236         add_filter_command( EXCLUDE_CLIP, "FilterClips", Accelerator( '7', (GdkModifierType)GDK_MOD1_MASK ) );
237         add_filter_command( EXCLUDE_PATHS, "FilterPaths", Accelerator( '8', (GdkModifierType)GDK_MOD1_MASK ) );
238         if ( g_pGameDescription->mGameType != "doom3" ) {
239                 add_filter_command( EXCLUDE_CLUSTERPORTALS, "FilterClusterportals", Accelerator( '9', (GdkModifierType)GDK_MOD1_MASK ) );
240         }
241         add_filter_command( EXCLUDE_LIGHTS, "FilterLights", Accelerator( '0', (GdkModifierType)GDK_MOD1_MASK ) );
242         add_filter_command( EXCLUDE_STRUCTURAL, "FilterStructural", Accelerator( 'D', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
243         if ( g_pGameDescription->mGameType != "doom3" ) {
244                 add_filter_command( EXCLUDE_LIGHTGRID, "FilterLightgrid", accelerator_null() );
245         }
246         add_filter_command( EXCLUDE_CURVES, "FilterPatches", Accelerator( 'P', (GdkModifierType)GDK_CONTROL_MASK ) );
247         add_filter_command( EXCLUDE_DETAILS, "FilterDetails", Accelerator( 'D', (GdkModifierType)GDK_CONTROL_MASK ) );
248         add_filter_command( EXCLUDE_HINTSSKIPS, "FilterHintsSkips", Accelerator( 'H', (GdkModifierType)GDK_CONTROL_MASK ) );
249         add_filter_command( EXCLUDE_MODELS, "FilterModels", Accelerator( 'M', (GdkModifierType)GDK_SHIFT_MASK ) );
250         add_filter_command( EXCLUDE_TRIGGERS, "FilterTriggers", Accelerator( 'T', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
251         if ( g_pGameDescription->mGameType != "doom3" ) {
252                 add_filter_command( EXCLUDE_BOTCLIP, "FilterBotClips", Accelerator( 'M', (GdkModifierType)GDK_MOD1_MASK ) );
253                 add_filter_command( EXCLUDE_DECALS, "FilterDecals", Accelerator( 'D', (GdkModifierType)GDK_SHIFT_MASK ) );
254         }
255
256         PerformFiltering();
257 }
258
259 void DestroyFilters(){
260         g_filters.clear();
261 }
262
263 #include "modulesystem/singletonmodule.h"
264 #include "modulesystem/moduleregistry.h"
265
266 class FilterAPI
267 {
268 FilterSystem* m_filter;
269 public:
270 typedef FilterSystem Type;
271 STRING_CONSTANT( Name, "*" );
272
273 FilterAPI(){
274         ConstructFilters();
275
276         m_filter = &GetFilterSystem();
277 }
278 ~FilterAPI(){
279         DestroyFilters();
280 }
281 FilterSystem* getTable(){
282         return m_filter;
283 }
284 };
285
286 typedef SingletonModule<FilterAPI> FilterModule;
287 typedef Static<FilterModule> StaticFilterModule;
288 StaticRegisterModule staticRegisterFilter( StaticFilterModule::instance() );