]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/mainframe.cpp
Remove some commented-out code
[xonotic/netradiant.git] / radiant / mainframe.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
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 //
23 // Main Window for Q3Radiant
24 //
25 // Leonardo Zide (leo@lokigames.com)
26 //
27
28 #include "mainframe.h"
29
30 #include "debugging/debugging.h"
31 #include "version.h"
32
33 #include "ifilesystem.h"
34 #include "iundo.h"
35 #include "ifilter.h"
36 #include "itoolbar.h"
37 #include "editable.h"
38 #include "ientity.h"
39 #include "ishaders.h"
40 #include "igl.h"
41 #include "moduleobserver.h"
42
43 #include <ctime>
44
45 #include <gdk/gdkkeysyms.h>
46 #include <gtk/gtkhbox.h>
47 #include <gtk/gtkvbox.h>
48 #include <gtk/gtkframe.h>
49 #include <gtk/gtklabel.h>
50 #include <gtk/gtkhpaned.h>
51 #include <gtk/gtkvpaned.h>
52 #include <gtk/gtktoolbar.h>
53 #include <gtk/gtkmenubar.h>
54 #include <gtk/gtkimage.h>
55 #include <gtk/gtktable.h>
56
57
58 #include "cmdlib.h"
59 #include "scenelib.h"
60 #include "stream/stringstream.h"
61 #include "signal/isignal.h"
62 #include "os/path.h"
63 #include "os/file.h"
64 #include "eclasslib.h"
65 #include "moduleobservers.h"
66
67 #include "gtkutil/clipboard.h"
68 #include "gtkutil/container.h"
69 #include "gtkutil/frame.h"
70 #include "gtkutil/glfont.h"
71 #include "gtkutil/glwidget.h"
72 #include "gtkutil/image.h"
73 #include "gtkutil/menu.h"
74 #include "gtkutil/paned.h"
75 #include "gtkutil/widget.h"
76
77 #include "autosave.h"
78 #include "build.h"
79 #include "brushmanip.h"
80 #include "brushmodule.h"
81 #include "camwindow.h"
82 #include "csg.h"
83 #include "commands.h"
84 #include "console.h"
85 #include "entity.h"
86 #include "entityinspector.h"
87 #include "entitylist.h"
88 #include "filters.h"
89 #include "findtexturedialog.h"
90 #include "grid.h"
91 #include "groupdialog.h"
92 #include "gtkdlgs.h"
93 #include "gtkmisc.h"
94 #include "help.h"
95 #include "map.h"
96 #include "mru.h"
97 #include "multimon.h"
98 #include "patchdialog.h"
99 #include "patchmanip.h"
100 #include "plugin.h"
101 #include "pluginmanager.h"
102 #include "pluginmenu.h"
103 #include "plugintoolbar.h"
104 #include "points.h"
105 #include "preferences.h"
106 #include "qe3.h"
107 #include "qgl.h"
108 #include "select.h"
109 #include "server.h"
110 #include "surfacedialog.h"
111 #include "textures.h"
112 #include "texwindow.h"
113 #include "url.h"
114 #include "xywindow.h"
115 #include "windowobservers.h"
116 #include "renderstate.h"
117 #include "feedback.h"
118 #include "referencecache.h"
119
120
121
122 struct layout_globals_t
123 {
124         WindowPosition m_position;
125
126
127         int nXYHeight;
128         int nXYWidth;
129         int nCamWidth;
130         int nCamHeight;
131         int nState;
132
133         layout_globals_t() :
134                 m_position( -1, -1, 640, 480 ),
135
136                 nXYHeight( 300 ),
137                 nXYWidth( 300 ),
138                 nCamWidth( 200 ),
139                 nCamHeight( 200 ),
140                 nState( GDK_WINDOW_STATE_MAXIMIZED ){
141         }
142 };
143
144 layout_globals_t g_layout_globals;
145 glwindow_globals_t g_glwindow_globals;
146
147
148 // VFS
149 class VFSModuleObserver : public ModuleObserver
150 {
151 std::size_t m_unrealised;
152 public:
153 VFSModuleObserver() : m_unrealised( 1 ){
154 }
155 void realise(){
156         if ( --m_unrealised == 0 ) {
157                 QE_InitVFS();
158                 GlobalFileSystem().initialise();
159         }
160 }
161 void unrealise(){
162         if ( ++m_unrealised == 1 ) {
163                 GlobalFileSystem().shutdown();
164         }
165 }
166 };
167
168 VFSModuleObserver g_VFSModuleObserver;
169
170 void VFS_Construct(){
171         Radiant_attachHomePathsObserver( g_VFSModuleObserver );
172 }
173 void VFS_Destroy(){
174         Radiant_detachHomePathsObserver( g_VFSModuleObserver );
175 }
176
177 // Home Paths
178
179 #ifdef WIN32
180 #include <shlobj.h>
181 #include <objbase.h>
182 const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}};
183 #define qREFKNOWNFOLDERID GUID
184 #define qKF_FLAG_CREATE 0x8000
185 #define qKF_FLAG_NO_ALIAS 0x1000
186 typedef HRESULT ( WINAPI qSHGetKnownFolderPath_t )( qREFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath );
187 static qSHGetKnownFolderPath_t *qSHGetKnownFolderPath;
188 #endif
189 void HomePaths_Realise(){
190         do
191         {
192                 const char* prefix = g_pGameDescription->getKeyValue( "prefix" );
193                 if ( !string_empty( prefix ) ) {
194                         StringOutputStream path( 256 );
195
196 #if defined( __APPLE__ )
197                         path.clear();
198                         path << DirectoryCleaned( g_get_home_dir() ) << "Library/Application Support" << ( prefix + 1 ) << "/";
199                         if ( file_is_directory( path.c_str() ) ) {
200                                 g_qeglobals.m_userEnginePath = path.c_str();
201                                 break;
202                         }
203                         path.clear();
204                         path << DirectoryCleaned( g_get_home_dir() ) << prefix << "/";
205 #endif
206
207 #if defined( WIN32 )
208                         TCHAR mydocsdir[MAX_PATH + 1];
209                         wchar_t *mydocsdirw;
210                         HMODULE shfolder = LoadLibrary( "shfolder.dll" );
211                         if ( shfolder ) {
212                                 qSHGetKnownFolderPath = (qSHGetKnownFolderPath_t *) GetProcAddress( shfolder, "SHGetKnownFolderPath" );
213                         }
214                         else{
215                                 qSHGetKnownFolderPath = NULL;
216                         }
217                         CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
218                         if ( qSHGetKnownFolderPath && qSHGetKnownFolderPath( qFOLDERID_SavedGames, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &mydocsdirw ) == S_OK ) {
219                                 memset( mydocsdir, 0, sizeof( mydocsdir ) );
220                                 wcstombs( mydocsdir, mydocsdirw, sizeof( mydocsdir ) - 1 );
221                                 CoTaskMemFree( mydocsdirw );
222                                 path.clear();
223                                 path << DirectoryCleaned( mydocsdir ) << ( prefix + 1 ) << "/";
224                                 if ( file_is_directory( path.c_str() ) ) {
225                                         g_qeglobals.m_userEnginePath = path.c_str();
226                                         CoUninitialize();
227                                         FreeLibrary( shfolder );
228                                         break;
229                                 }
230                         }
231                         CoUninitialize();
232                         if ( shfolder ) {
233                                 FreeLibrary( shfolder );
234                         }
235                         if ( SHGetFolderPath( NULL, CSIDL_PERSONAL, NULL, 0, mydocsdir ) ) {
236                                 path.clear();
237                                 path << DirectoryCleaned( mydocsdir ) << "My Games/" << ( prefix + 1 ) << "/";
238                                 // win32: only add it if it already exists
239                                 if ( file_is_directory( path.c_str() ) ) {
240                                         g_qeglobals.m_userEnginePath = path.c_str();
241                                         break;
242                                 }
243                         }
244 #endif
245
246 #if defined( POSIX )
247                         path.clear();
248                         path << DirectoryCleaned( g_get_home_dir() ) << prefix << "/";
249                         g_qeglobals.m_userEnginePath = path.c_str();
250                         break;
251 #endif
252                 }
253
254                 g_qeglobals.m_userEnginePath = EnginePath_get();
255         }
256         while ( 0 );
257
258         Q_mkdir( g_qeglobals.m_userEnginePath.c_str() );
259
260         {
261                 StringOutputStream path( 256 );
262                 path << g_qeglobals.m_userEnginePath.c_str() << gamename_get() << '/';
263                 g_qeglobals.m_userGamePath = path.c_str();
264         }
265         ASSERT_MESSAGE( !string_empty( g_qeglobals.m_userGamePath.c_str() ), "HomePaths_Realise: user-game-path is empty" );
266         Q_mkdir( g_qeglobals.m_userGamePath.c_str() );
267 }
268
269 ModuleObservers g_homePathObservers;
270
271 void Radiant_attachHomePathsObserver( ModuleObserver& observer ){
272         g_homePathObservers.attach( observer );
273 }
274
275 void Radiant_detachHomePathsObserver( ModuleObserver& observer ){
276         g_homePathObservers.detach( observer );
277 }
278
279 class HomePathsModuleObserver : public ModuleObserver
280 {
281 std::size_t m_unrealised;
282 public:
283 HomePathsModuleObserver() : m_unrealised( 1 ){
284 }
285 void realise(){
286         if ( --m_unrealised == 0 ) {
287                 HomePaths_Realise();
288                 g_homePathObservers.realise();
289         }
290 }
291 void unrealise(){
292         if ( ++m_unrealised == 1 ) {
293                 g_homePathObservers.unrealise();
294         }
295 }
296 };
297
298 HomePathsModuleObserver g_HomePathsModuleObserver;
299
300 void HomePaths_Construct(){
301         Radiant_attachEnginePathObserver( g_HomePathsModuleObserver );
302 }
303 void HomePaths_Destroy(){
304         Radiant_detachEnginePathObserver( g_HomePathsModuleObserver );
305 }
306
307
308 // Engine Path
309
310 CopiedString g_strEnginePath;
311 ModuleObservers g_enginePathObservers;
312 std::size_t g_enginepath_unrealised = 1;
313
314 void Radiant_attachEnginePathObserver( ModuleObserver& observer ){
315         g_enginePathObservers.attach( observer );
316 }
317
318 void Radiant_detachEnginePathObserver( ModuleObserver& observer ){
319         g_enginePathObservers.detach( observer );
320 }
321
322
323 void EnginePath_Realise(){
324         if ( --g_enginepath_unrealised == 0 ) {
325                 g_enginePathObservers.realise();
326         }
327 }
328
329
330 const char* EnginePath_get(){
331         ASSERT_MESSAGE( g_enginepath_unrealised == 0, "EnginePath_get: engine path not realised" );
332         return g_strEnginePath.c_str();
333 }
334
335 void EnginePath_Unrealise(){
336         if ( ++g_enginepath_unrealised == 1 ) {
337                 g_enginePathObservers.unrealise();
338         }
339 }
340
341 void setEnginePath( const char* path ){
342         StringOutputStream buffer( 256 );
343         buffer << DirectoryCleaned( path );
344         if ( !path_equal( buffer.c_str(), g_strEnginePath.c_str() ) ) {
345
346                 ScopeDisableScreenUpdates disableScreenUpdates( "Processing...", "Changing Engine Path" );
347
348                 EnginePath_Unrealise();
349
350                 g_strEnginePath = buffer.c_str();
351
352                 EnginePath_Realise();
353         }
354 }
355
356
357 // App Path
358
359 CopiedString g_strAppPath;                 ///< holds the full path of the executable
360
361 const char* AppPath_get(){
362         return g_strAppPath.c_str();
363 }
364
365 /// the path to the local rc-dir
366 const char* LocalRcPath_get( void ){
367         static CopiedString rc_path;
368         if ( rc_path.empty() ) {
369                 StringOutputStream stream( 256 );
370                 stream << GlobalRadiant().getSettingsPath() << g_pGameDescription->mGameFile.c_str() << "/";
371                 rc_path = stream.c_str();
372         }
373         return rc_path.c_str();
374 }
375
376 /// directory for temp files
377 /// NOTE: on *nix this is were we check for .pid
378 CopiedString g_strSettingsPath;
379 const char* SettingsPath_get(){
380         return g_strSettingsPath.c_str();
381 }
382
383
384 /*!
385    points to the game tools directory, for instance
386    C:/Program Files/Quake III Arena/GtkRadiant
387    (or other games)
388    this is one of the main variables that are configured by the game selection on startup
389    [GameToolsPath]/plugins
390    [GameToolsPath]/modules
391    and also q3map, bspc
392  */
393 CopiedString g_strGameToolsPath;           ///< this is set by g_GamesDialog
394
395 const char* GameToolsPath_get(){
396         return g_strGameToolsPath.c_str();
397 }
398
399 void EnginePathImport( CopiedString& self, const char* value ){
400         setEnginePath( value );
401 }
402 typedef ReferenceCaller1<CopiedString, const char*, EnginePathImport> EnginePathImportCaller;
403
404 void Paths_constructPreferences( PreferencesPage& page ){
405         page.appendPathEntry( "Engine Path", true,
406                                                   StringImportCallback( EnginePathImportCaller( g_strEnginePath ) ),
407                                                   StringExportCallback( StringExportCaller( g_strEnginePath ) )
408                                                   );
409 }
410 void Paths_constructPage( PreferenceGroup& group ){
411         PreferencesPage page( group.createPage( "Paths", "Path Settings" ) );
412         Paths_constructPreferences( page );
413 }
414 void Paths_registerPreferencesPage(){
415         PreferencesDialog_addSettingsPage( FreeCaller1<PreferenceGroup&, Paths_constructPage>() );
416 }
417
418
419 class PathsDialog : public Dialog
420 {
421 public:
422 GtkWindow* BuildDialog(){
423         GtkFrame* frame = create_dialog_frame( "Path settings", GTK_SHADOW_ETCHED_IN );
424
425         GtkVBox* vbox2 = create_dialog_vbox( 0, 4 );
426         gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( vbox2 ) );
427
428         {
429                 PreferencesPage preferencesPage( *this, GTK_WIDGET( vbox2 ) );
430                 Paths_constructPreferences( preferencesPage );
431         }
432
433         return create_simple_modal_dialog_window( "Engine Path Not Found", m_modal, GTK_WIDGET( frame ) );
434 }
435 };
436
437 PathsDialog g_PathsDialog;
438
439 void EnginePath_verify(){
440         if ( !file_exists( g_strEnginePath.c_str() ) ) {
441                 g_PathsDialog.Create();
442                 g_PathsDialog.DoModal();
443                 g_PathsDialog.Destroy();
444         }
445 }
446
447 namespace
448 {
449 CopiedString g_gamename;
450 CopiedString g_gamemode;
451 ModuleObservers g_gameNameObservers;
452 ModuleObservers g_gameModeObservers;
453 }
454
455 void Radiant_attachGameNameObserver( ModuleObserver& observer ){
456         g_gameNameObservers.attach( observer );
457 }
458
459 void Radiant_detachGameNameObserver( ModuleObserver& observer ){
460         g_gameNameObservers.detach( observer );
461 }
462
463 const char* basegame_get(){
464         return g_pGameDescription->getRequiredKeyValue( "basegame" );
465 }
466
467 const char* gamename_get(){
468         const char* gamename = g_gamename.c_str();
469         if ( string_empty( gamename ) ) {
470                 return basegame_get();
471         }
472         return gamename;
473 }
474
475 void gamename_set( const char* gamename ){
476         if ( !string_equal( gamename, g_gamename.c_str() ) ) {
477                 g_gameNameObservers.unrealise();
478                 g_gamename = gamename;
479                 g_gameNameObservers.realise();
480         }
481 }
482
483 void Radiant_attachGameModeObserver( ModuleObserver& observer ){
484         g_gameModeObservers.attach( observer );
485 }
486
487 void Radiant_detachGameModeObserver( ModuleObserver& observer ){
488         g_gameModeObservers.detach( observer );
489 }
490
491 const char* gamemode_get(){
492         return g_gamemode.c_str();
493 }
494
495 void gamemode_set( const char* gamemode ){
496         if ( !string_equal( gamemode, g_gamemode.c_str() ) ) {
497                 g_gameModeObservers.unrealise();
498                 g_gamemode = gamemode;
499                 g_gameModeObservers.realise();
500         }
501 }
502
503 #include "os/dir.h"
504
505 class CLoadModule
506 {
507 const char* m_path;
508 public:
509 CLoadModule( const char* path ) : m_path( path ){
510 }
511 void operator()( const char* name ) const {
512         char fullname[1024];
513         ASSERT_MESSAGE( strlen( m_path ) + strlen( name ) < 1024, "" );
514         strcpy( fullname, m_path );
515         strcat( fullname, name );
516         globalOutputStream() << "Found '" << fullname << "'\n";
517         GlobalModuleServer_loadModule( fullname );
518 }
519 };
520
521 const char* const c_library_extension =
522 #if defined( CMAKE_SHARED_MODULE_SUFFIX )
523     CMAKE_SHARED_MODULE_SUFFIX
524 #elif defined( WIN32 )
525         "dll"
526 #elif defined ( __APPLE__ )
527         "dylib"
528 #elif defined( __linux__ ) || defined ( __FreeBSD__ )
529         "so"
530 #endif
531 ;
532
533 void Radiant_loadModules( const char* path ){
534         Directory_forEach( path, MatchFileExtension<CLoadModule>( c_library_extension, CLoadModule( path ) ) );
535 }
536
537 void Radiant_loadModulesFromRoot( const char* directory ){
538         {
539                 StringOutputStream path( 256 );
540                 path << directory << g_pluginsDir;
541                 Radiant_loadModules( path.c_str() );
542         }
543
544         if ( !string_equal( g_pluginsDir, g_modulesDir ) ) {
545                 StringOutputStream path( 256 );
546                 path << directory << g_modulesDir;
547                 Radiant_loadModules( path.c_str() );
548         }
549 }
550
551 //! Make COLOR_BRUSHES override worldspawn eclass colour.
552 void SetWorldspawnColour( const Vector3& colour ){
553         EntityClass* worldspawn = GlobalEntityClassManager().findOrInsert( "worldspawn", true );
554         eclass_release_state( worldspawn );
555         worldspawn->color = colour;
556         eclass_capture_state( worldspawn );
557 }
558
559
560 class WorldspawnColourEntityClassObserver : public ModuleObserver
561 {
562 std::size_t m_unrealised;
563 public:
564 WorldspawnColourEntityClassObserver() : m_unrealised( 1 ){
565 }
566 void realise(){
567         if ( --m_unrealised == 0 ) {
568                 SetWorldspawnColour( g_xywindow_globals.color_brushes );
569         }
570 }
571 void unrealise(){
572         if ( ++m_unrealised == 1 ) {
573         }
574 }
575 };
576
577 WorldspawnColourEntityClassObserver g_WorldspawnColourEntityClassObserver;
578
579
580 ModuleObservers g_gameToolsPathObservers;
581
582 void Radiant_attachGameToolsPathObserver( ModuleObserver& observer ){
583         g_gameToolsPathObservers.attach( observer );
584 }
585
586 void Radiant_detachGameToolsPathObserver( ModuleObserver& observer ){
587         g_gameToolsPathObservers.detach( observer );
588 }
589
590 void Radiant_Initialise(){
591         GlobalModuleServer_Initialise();
592
593         Radiant_loadModulesFromRoot( AppPath_get() );
594
595         Preferences_Load();
596
597         bool success = Radiant_Construct( GlobalModuleServer_get() );
598         ASSERT_MESSAGE( success, "module system failed to initialise - see radiant.log for error messages" );
599
600         g_gameToolsPathObservers.realise();
601         g_gameModeObservers.realise();
602         g_gameNameObservers.realise();
603 }
604
605 void Radiant_Shutdown(){
606         g_gameNameObservers.unrealise();
607         g_gameModeObservers.unrealise();
608         g_gameToolsPathObservers.unrealise();
609
610         if ( !g_preferences_globals.disable_ini ) {
611                 globalOutputStream() << "Start writing prefs\n";
612                 Preferences_Save();
613                 globalOutputStream() << "Done prefs\n";
614         }
615
616         Radiant_Destroy();
617
618         GlobalModuleServer_Shutdown();
619 }
620
621 void Exit(){
622         if ( ConfirmModified( "Exit Radiant" ) ) {
623                 gtk_main_quit();
624         }
625 }
626
627
628 void Undo(){
629         GlobalUndoSystem().undo();
630         SceneChangeNotify();
631 }
632
633 void Redo(){
634         GlobalUndoSystem().redo();
635         SceneChangeNotify();
636 }
637
638 void deleteSelection(){
639         UndoableCommand undo( "deleteSelected" );
640         Select_Delete();
641 }
642
643 void Map_ExportSelected( TextOutputStream& ostream ){
644         Map_ExportSelected( ostream, Map_getFormat( g_map ) );
645 }
646
647 void Map_ImportSelected( TextInputStream& istream ){
648         Map_ImportSelected( istream, Map_getFormat( g_map ) );
649 }
650
651 void Selection_Copy(){
652         clipboard_copy( Map_ExportSelected );
653 }
654
655 void Selection_Paste(){
656         clipboard_paste( Map_ImportSelected );
657 }
658
659 void Copy(){
660         if ( SelectedFaces_empty() ) {
661                 Selection_Copy();
662         }
663         else
664         {
665                 SelectedFaces_copyTexture();
666         }
667 }
668
669 void Paste(){
670         if ( SelectedFaces_empty() ) {
671                 UndoableCommand undo( "paste" );
672
673                 GlobalSelectionSystem().setSelectedAll( false );
674                 Selection_Paste();
675         }
676         else
677         {
678                 SelectedFaces_pasteTexture();
679         }
680 }
681
682 void PasteToCamera(){
683         CamWnd& camwnd = *g_pParentWnd->GetCamWnd();
684         GlobalSelectionSystem().setSelectedAll( false );
685
686         UndoableCommand undo( "pasteToCamera" );
687
688         Selection_Paste();
689
690         // Work out the delta
691         Vector3 mid;
692         Select_GetMid( mid );
693         Vector3 delta = vector3_subtracted( vector3_snapped( Camera_getOrigin( camwnd ), GetSnapGridSize() ), mid );
694
695         // Move to camera
696         GlobalSelectionSystem().translateSelected( delta );
697 }
698
699
700 void ColorScheme_Original(){
701         TextureBrowser_setBackgroundColour( GlobalTextureBrowser(), Vector3( 0.25f, 0.25f, 0.25f ) );
702
703         g_camwindow_globals.color_selbrushes3d = Vector3( 1.0f, 0.0f, 0.0f );
704         g_camwindow_globals.color_cameraback = Vector3( 0.25f, 0.25f, 0.25f );
705         CamWnd_Update( *g_pParentWnd->GetCamWnd() );
706
707         g_xywindow_globals.color_gridback = Vector3( 1.0f, 1.0f, 1.0f );
708         g_xywindow_globals.color_gridminor = Vector3( 0.75f, 0.75f, 0.75f );
709         g_xywindow_globals.color_gridmajor = Vector3( 0.5f, 0.5f, 0.5f );
710         g_xywindow_globals.color_gridminor_alt = Vector3( 0.5f, 0.0f, 0.0f );
711         g_xywindow_globals.color_gridmajor_alt = Vector3( 1.0f, 0.0f, 0.0f );
712         g_xywindow_globals.color_gridblock = Vector3( 0.0f, 0.0f, 1.0f );
713         g_xywindow_globals.color_gridtext = Vector3( 0.0f, 0.0f, 0.0f );
714         g_xywindow_globals.color_selbrushes = Vector3( 1.0f, 0.0f, 0.0f );
715         g_xywindow_globals.color_clipper = Vector3( 0.0f, 0.0f, 1.0f );
716         g_xywindow_globals.color_brushes = Vector3( 0.0f, 0.0f, 0.0f );
717         SetWorldspawnColour( g_xywindow_globals.color_brushes );
718         g_xywindow_globals.color_viewname = Vector3( 0.5f, 0.0f, 0.75f );
719         XY_UpdateAllWindows();
720 }
721
722 void ColorScheme_QER(){
723         TextureBrowser_setBackgroundColour( GlobalTextureBrowser(), Vector3( 0.25f, 0.25f, 0.25f ) );
724
725         g_camwindow_globals.color_cameraback = Vector3( 0.25f, 0.25f, 0.25f );
726         g_camwindow_globals.color_selbrushes3d = Vector3( 1.0f, 0.0f, 0.0f );
727         CamWnd_Update( *g_pParentWnd->GetCamWnd() );
728
729         g_xywindow_globals.color_gridback = Vector3( 1.0f, 1.0f, 1.0f );
730         g_xywindow_globals.color_gridminor = Vector3( 1.0f, 1.0f, 1.0f );
731         g_xywindow_globals.color_gridmajor = Vector3( 0.5f, 0.5f, 0.5f );
732         g_xywindow_globals.color_gridblock = Vector3( 0.0f, 0.0f, 1.0f );
733         g_xywindow_globals.color_gridtext = Vector3( 0.0f, 0.0f, 0.0f );
734         g_xywindow_globals.color_selbrushes = Vector3( 1.0f, 0.0f, 0.0f );
735         g_xywindow_globals.color_clipper = Vector3( 0.0f, 0.0f, 1.0f );
736         g_xywindow_globals.color_brushes = Vector3( 0.0f, 0.0f, 0.0f );
737         SetWorldspawnColour( g_xywindow_globals.color_brushes );
738         g_xywindow_globals.color_viewname = Vector3( 0.5f, 0.0f, 0.75f );
739         XY_UpdateAllWindows();
740 }
741
742 void ColorScheme_Black(){
743         TextureBrowser_setBackgroundColour( GlobalTextureBrowser(), Vector3( 0.25f, 0.25f, 0.25f ) );
744
745         g_camwindow_globals.color_cameraback = Vector3( 0.25f, 0.25f, 0.25f );
746         g_camwindow_globals.color_selbrushes3d = Vector3( 1.0f, 0.0f, 0.0f );
747         CamWnd_Update( *g_pParentWnd->GetCamWnd() );
748
749         g_xywindow_globals.color_gridback = Vector3( 0.0f, 0.0f, 0.0f );
750         g_xywindow_globals.color_gridminor = Vector3( 0.2f, 0.2f, 0.2f );
751         g_xywindow_globals.color_gridmajor = Vector3( 0.3f, 0.5f, 0.5f );
752         g_xywindow_globals.color_gridblock = Vector3( 0.0f, 0.0f, 1.0f );
753         g_xywindow_globals.color_gridtext = Vector3( 1.0f, 1.0f, 1.0f );
754         g_xywindow_globals.color_selbrushes = Vector3( 1.0f, 0.0f, 0.0f );
755         g_xywindow_globals.color_clipper = Vector3( 0.0f, 0.0f, 1.0f );
756         g_xywindow_globals.color_brushes = Vector3( 1.0f, 1.0f, 1.0f );
757         SetWorldspawnColour( g_xywindow_globals.color_brushes );
758         g_xywindow_globals.color_viewname = Vector3( 0.7f, 0.7f, 0.0f );
759         XY_UpdateAllWindows();
760 }
761
762 /* ydnar: to emulate maya/max/lightwave color schemes */
763 void ColorScheme_Ydnar(){
764         TextureBrowser_setBackgroundColour( GlobalTextureBrowser(), Vector3( 0.25f, 0.25f, 0.25f ) );
765
766         g_camwindow_globals.color_cameraback = Vector3( 0.25f, 0.25f, 0.25f );
767         g_camwindow_globals.color_selbrushes3d = Vector3( 1.0f, 0.0f, 0.0f );
768         CamWnd_Update( *g_pParentWnd->GetCamWnd() );
769
770         g_xywindow_globals.color_gridback = Vector3( 0.77f, 0.77f, 0.77f );
771         g_xywindow_globals.color_gridminor = Vector3( 0.83f, 0.83f, 0.83f );
772         g_xywindow_globals.color_gridmajor = Vector3( 0.89f, 0.89f, 0.89f );
773         g_xywindow_globals.color_gridblock = Vector3( 1.0f, 1.0f, 1.0f );
774         g_xywindow_globals.color_gridtext = Vector3( 0.0f, 0.0f, 0.0f );
775         g_xywindow_globals.color_selbrushes = Vector3( 1.0f, 0.0f, 0.0f );
776         g_xywindow_globals.color_clipper = Vector3( 0.0f, 0.0f, 1.0f );
777         g_xywindow_globals.color_brushes = Vector3( 0.0f, 0.0f, 0.0f );
778         SetWorldspawnColour( g_xywindow_globals.color_brushes );
779         g_xywindow_globals.color_viewname = Vector3( 0.5f, 0.0f, 0.75f );
780         XY_UpdateAllWindows();
781 }
782
783 typedef Callback1<Vector3&> GetColourCallback;
784 typedef Callback1<const Vector3&> SetColourCallback;
785
786 class ChooseColour
787 {
788 GetColourCallback m_get;
789 SetColourCallback m_set;
790 public:
791 ChooseColour( const GetColourCallback& get, const SetColourCallback& set )
792         : m_get( get ), m_set( set ){
793 }
794 void operator()(){
795         Vector3 colour;
796         m_get( colour );
797         color_dialog( GTK_WIDGET( MainFrame_getWindow() ), colour );
798         m_set( colour );
799 }
800 };
801
802
803
804 void Colour_get( const Vector3& colour, Vector3& other ){
805         other = colour;
806 }
807 typedef ConstReferenceCaller1<Vector3, Vector3&, Colour_get> ColourGetCaller;
808
809 void Colour_set( Vector3& colour, const Vector3& other ){
810         colour = other;
811         SceneChangeNotify();
812 }
813 typedef ReferenceCaller1<Vector3, const Vector3&, Colour_set> ColourSetCaller;
814
815 void BrushColour_set( const Vector3& other ){
816         g_xywindow_globals.color_brushes = other;
817         SetWorldspawnColour( g_xywindow_globals.color_brushes );
818         SceneChangeNotify();
819 }
820 typedef FreeCaller1<const Vector3&, BrushColour_set> BrushColourSetCaller;
821
822 void ClipperColour_set( const Vector3& other ){
823         g_xywindow_globals.color_clipper = other;
824         Brush_clipperColourChanged();
825         SceneChangeNotify();
826 }
827 typedef FreeCaller1<const Vector3&, ClipperColour_set> ClipperColourSetCaller;
828
829 void TextureBrowserColour_get( Vector3& other ){
830         other = TextureBrowser_getBackgroundColour( GlobalTextureBrowser() );
831 }
832 typedef FreeCaller1<Vector3&, TextureBrowserColour_get> TextureBrowserColourGetCaller;
833
834 void TextureBrowserColour_set( const Vector3& other ){
835         TextureBrowser_setBackgroundColour( GlobalTextureBrowser(), other );
836 }
837 typedef FreeCaller1<const Vector3&, TextureBrowserColour_set> TextureBrowserColourSetCaller;
838
839
840 class ColoursMenu
841 {
842 public:
843 ChooseColour m_textureback;
844 ChooseColour m_xyback;
845 ChooseColour m_gridmajor;
846 ChooseColour m_gridminor;
847 ChooseColour m_gridmajor_alt;
848 ChooseColour m_gridminor_alt;
849 ChooseColour m_gridtext;
850 ChooseColour m_gridblock;
851 ChooseColour m_cameraback;
852 ChooseColour m_brush;
853 ChooseColour m_selectedbrush;
854 ChooseColour m_selectedbrush3d;
855 ChooseColour m_clipper;
856 ChooseColour m_viewname;
857
858 ColoursMenu() :
859         m_textureback( TextureBrowserColourGetCaller(), TextureBrowserColourSetCaller() ),
860         m_xyback( ColourGetCaller( g_xywindow_globals.color_gridback ), ColourSetCaller( g_xywindow_globals.color_gridback ) ),
861         m_gridmajor( ColourGetCaller( g_xywindow_globals.color_gridmajor ), ColourSetCaller( g_xywindow_globals.color_gridmajor ) ),
862         m_gridminor( ColourGetCaller( g_xywindow_globals.color_gridminor ), ColourSetCaller( g_xywindow_globals.color_gridminor ) ),
863         m_gridmajor_alt( ColourGetCaller( g_xywindow_globals.color_gridmajor_alt ), ColourSetCaller( g_xywindow_globals.color_gridmajor_alt ) ),
864         m_gridminor_alt( ColourGetCaller( g_xywindow_globals.color_gridminor_alt ), ColourSetCaller( g_xywindow_globals.color_gridminor_alt ) ),
865         m_gridtext( ColourGetCaller( g_xywindow_globals.color_gridtext ), ColourSetCaller( g_xywindow_globals.color_gridtext ) ),
866         m_gridblock( ColourGetCaller( g_xywindow_globals.color_gridblock ), ColourSetCaller( g_xywindow_globals.color_gridblock ) ),
867         m_cameraback( ColourGetCaller( g_camwindow_globals.color_cameraback ), ColourSetCaller( g_camwindow_globals.color_cameraback ) ),
868         m_brush( ColourGetCaller( g_xywindow_globals.color_brushes ), BrushColourSetCaller() ),
869         m_selectedbrush( ColourGetCaller( g_xywindow_globals.color_selbrushes ), ColourSetCaller( g_xywindow_globals.color_selbrushes ) ),
870         m_selectedbrush3d( ColourGetCaller( g_camwindow_globals.color_selbrushes3d ), ColourSetCaller( g_camwindow_globals.color_selbrushes3d ) ),
871         m_clipper( ColourGetCaller( g_xywindow_globals.color_clipper ), ClipperColourSetCaller() ),
872         m_viewname( ColourGetCaller( g_xywindow_globals.color_viewname ), ColourSetCaller( g_xywindow_globals.color_viewname ) ){
873 }
874 };
875
876 ColoursMenu g_ColoursMenu;
877
878 GtkMenuItem* create_colours_menu(){
879         GtkMenuItem* colours_menu_item = new_sub_menu_item_with_mnemonic( "Colors" );
880         GtkMenu* menu_in_menu = GTK_MENU( gtk_menu_item_get_submenu( colours_menu_item ) );
881         if ( g_Layout_enableDetachableMenus.m_value ) {
882                 menu_tearoff( menu_in_menu );
883         }
884
885         GtkMenu* menu_3 = create_sub_menu_with_mnemonic( menu_in_menu, "Themes" );
886         if ( g_Layout_enableDetachableMenus.m_value ) {
887                 menu_tearoff( menu_3 );
888         }
889
890         create_menu_item_with_mnemonic( menu_3, "QE4 Original", "ColorSchemeOriginal" );
891         create_menu_item_with_mnemonic( menu_3, "Q3Radiant Original", "ColorSchemeQER" );
892         create_menu_item_with_mnemonic( menu_3, "Black and Green", "ColorSchemeBlackAndGreen" );
893         create_menu_item_with_mnemonic( menu_3, "Maya/Max/Lightwave Emulation", "ColorSchemeYdnar" );
894
895         menu_separator( menu_in_menu );
896
897         create_menu_item_with_mnemonic( menu_in_menu, "_Texture Background...", "ChooseTextureBackgroundColor" );
898         create_menu_item_with_mnemonic( menu_in_menu, "Grid Background...", "ChooseGridBackgroundColor" );
899         create_menu_item_with_mnemonic( menu_in_menu, "Grid Major...", "ChooseGridMajorColor" );
900         create_menu_item_with_mnemonic( menu_in_menu, "Grid Minor...", "ChooseGridMinorColor" );
901         create_menu_item_with_mnemonic( menu_in_menu, "Grid Major Small...", "ChooseSmallGridMajorColor" );
902         create_menu_item_with_mnemonic( menu_in_menu, "Grid Minor Small...", "ChooseSmallGridMinorColor" );
903         create_menu_item_with_mnemonic( menu_in_menu, "Grid Text...", "ChooseGridTextColor" );
904         create_menu_item_with_mnemonic( menu_in_menu, "Grid Block...", "ChooseGridBlockColor" );
905         create_menu_item_with_mnemonic( menu_in_menu, "Default Brush...", "ChooseBrushColor" );
906         create_menu_item_with_mnemonic( menu_in_menu, "Camera Background...", "ChooseCameraBackgroundColor" );
907         create_menu_item_with_mnemonic( menu_in_menu, "Selected Brush...", "ChooseSelectedBrushColor" );
908         create_menu_item_with_mnemonic( menu_in_menu, "Selected Brush (Camera)...", "ChooseCameraSelectedBrushColor" );
909         create_menu_item_with_mnemonic( menu_in_menu, "Clipper...", "ChooseClipperColor" );
910         create_menu_item_with_mnemonic( menu_in_menu, "Active View name...", "ChooseOrthoViewNameColor" );
911
912         return colours_menu_item;
913 }
914
915
916 void Restart(){
917         PluginsMenu_clear();
918         PluginToolbar_clear();
919
920         Radiant_Shutdown();
921         Radiant_Initialise();
922
923         PluginsMenu_populate();
924
925         PluginToolbar_populate();
926 }
927
928
929 void thunk_OnSleep(){
930         g_pParentWnd->OnSleep();
931 }
932
933 void OpenUpdateURL(){
934         // build the URL
935         StringOutputStream URL( 256 );
936         URL << "http://www.icculus.org/netradiant/?cmd=update&data=dlupdate&query_dlup=1";
937 #ifdef WIN32
938         URL << "&OS_dlup=1";
939 #elif defined( __APPLE__ )
940         URL << "&OS_dlup=2";
941 #else
942         URL << "&OS_dlup=3";
943 #endif
944         URL << "&Version_dlup=" RADIANT_VERSION;
945         g_GamesDialog.AddPacksURL( URL );
946         OpenURL( URL.c_str() );
947 }
948
949 // open the Q3Rad manual
950 void OpenHelpURL(){
951         // at least on win32, AppPath + "docs/index.html"
952         StringOutputStream help( 256 );
953         help << AppPath_get() << "docs/index.html";
954         OpenURL( help.c_str() );
955 }
956
957 void OpenBugReportURL(){
958         OpenURL( "http://www.icculus.org/netradiant/?cmd=bugs" );
959 }
960
961
962 GtkWidget* g_page_console;
963
964 void Console_ToggleShow(){
965         GroupDialog_showPage( g_page_console );
966 }
967
968 GtkWidget* g_page_entity;
969
970 void EntityInspector_ToggleShow(){
971         GroupDialog_showPage( g_page_entity );
972 }
973
974
975
976 void SetClipMode( bool enable );
977 void ModeChangeNotify();
978
979 typedef void ( *ToolMode )();
980 ToolMode g_currentToolMode = 0;
981 bool g_currentToolModeSupportsComponentEditing = false;
982 ToolMode g_defaultToolMode = 0;
983
984
985
986 void SelectionSystem_DefaultMode(){
987         GlobalSelectionSystem().SetMode( SelectionSystem::ePrimitive );
988         GlobalSelectionSystem().SetComponentMode( SelectionSystem::eDefault );
989         ModeChangeNotify();
990 }
991
992
993 bool EdgeMode(){
994         return GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
995                    && GlobalSelectionSystem().ComponentMode() == SelectionSystem::eEdge;
996 }
997
998 bool VertexMode(){
999         return GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1000                    && GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex;
1001 }
1002
1003 bool FaceMode(){
1004         return GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1005                    && GlobalSelectionSystem().ComponentMode() == SelectionSystem::eFace;
1006 }
1007
1008 template<bool( *BoolFunction ) ( )>
1009 class BoolFunctionExport
1010 {
1011 public:
1012 static void apply( const BoolImportCallback& importCallback ){
1013         importCallback( BoolFunction() );
1014 }
1015 };
1016
1017 typedef FreeCaller1<const BoolImportCallback&, &BoolFunctionExport<EdgeMode>::apply> EdgeModeApplyCaller;
1018 EdgeModeApplyCaller g_edgeMode_button_caller;
1019 BoolExportCallback g_edgeMode_button_callback( g_edgeMode_button_caller );
1020 ToggleItem g_edgeMode_button( g_edgeMode_button_callback );
1021
1022 typedef FreeCaller1<const BoolImportCallback&, &BoolFunctionExport<VertexMode>::apply> VertexModeApplyCaller;
1023 VertexModeApplyCaller g_vertexMode_button_caller;
1024 BoolExportCallback g_vertexMode_button_callback( g_vertexMode_button_caller );
1025 ToggleItem g_vertexMode_button( g_vertexMode_button_callback );
1026
1027 typedef FreeCaller1<const BoolImportCallback&, &BoolFunctionExport<FaceMode>::apply> FaceModeApplyCaller;
1028 FaceModeApplyCaller g_faceMode_button_caller;
1029 BoolExportCallback g_faceMode_button_callback( g_faceMode_button_caller );
1030 ToggleItem g_faceMode_button( g_faceMode_button_callback );
1031
1032 void ComponentModeChanged(){
1033         g_edgeMode_button.update();
1034         g_vertexMode_button.update();
1035         g_faceMode_button.update();
1036 }
1037
1038 void ComponentMode_SelectionChanged( const Selectable& selectable ){
1039         if ( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1040                  && GlobalSelectionSystem().countSelected() == 0 ) {
1041                 SelectionSystem_DefaultMode();
1042                 ComponentModeChanged();
1043         }
1044 }
1045
1046 void SelectEdgeMode(){
1047
1048         if ( EdgeMode() ) {
1049                 SelectionSystem_DefaultMode();
1050         }
1051         else if ( GlobalSelectionSystem().countSelected() != 0 ) {
1052                 if ( !g_currentToolModeSupportsComponentEditing ) {
1053                         g_defaultToolMode();
1054                 }
1055
1056                 GlobalSelectionSystem().SetMode( SelectionSystem::eComponent );
1057                 GlobalSelectionSystem().SetComponentMode( SelectionSystem::eEdge );
1058         }
1059
1060         ComponentModeChanged();
1061
1062         ModeChangeNotify();
1063 }
1064
1065 void SelectVertexMode(){
1066
1067         if ( VertexMode() ) {
1068                 SelectionSystem_DefaultMode();
1069         }
1070         else if ( GlobalSelectionSystem().countSelected() != 0 ) {
1071                 if ( !g_currentToolModeSupportsComponentEditing ) {
1072                         g_defaultToolMode();
1073                 }
1074
1075                 GlobalSelectionSystem().SetMode( SelectionSystem::eComponent );
1076                 GlobalSelectionSystem().SetComponentMode( SelectionSystem::eVertex );
1077         }
1078
1079         ComponentModeChanged();
1080
1081         ModeChangeNotify();
1082 }
1083
1084 void SelectFaceMode(){
1085
1086         if ( FaceMode() ) {
1087                 SelectionSystem_DefaultMode();
1088         }
1089         else if ( GlobalSelectionSystem().countSelected() != 0 ) {
1090                 if ( !g_currentToolModeSupportsComponentEditing ) {
1091                         g_defaultToolMode();
1092                 }
1093
1094                 GlobalSelectionSystem().SetMode( SelectionSystem::eComponent );
1095                 GlobalSelectionSystem().SetComponentMode( SelectionSystem::eFace );
1096         }
1097
1098         ComponentModeChanged();
1099
1100         ModeChangeNotify();
1101 }
1102
1103
1104 class CloneSelected : public scene::Graph::Walker
1105 {
1106 bool doMakeUnique;
1107 NodeSmartReference worldspawn;
1108 public:
1109 CloneSelected( bool d ) : doMakeUnique( d ), worldspawn( Map_FindOrInsertWorldspawn( g_map ) ){
1110 }
1111 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1112         if ( path.size() == 1 ) {
1113                 return true;
1114         }
1115
1116         // ignore worldspawn, but keep checking children
1117         NodeSmartReference me( path.top().get() );
1118         if ( me == worldspawn ) {
1119                 return true;
1120         }
1121
1122         if ( !path.top().get().isRoot() ) {
1123                 Selectable* selectable = Instance_getSelectable( instance );
1124                 if ( selectable != 0
1125                          && selectable->isSelected() ) {
1126                         return false;
1127                 }
1128         }
1129
1130         return true;
1131 }
1132 void post( const scene::Path& path, scene::Instance& instance ) const {
1133         if ( path.size() == 1 ) {
1134                 return;
1135         }
1136
1137         // ignore worldspawn, but keep checking children
1138         NodeSmartReference me( path.top().get() );
1139         if ( me == worldspawn ) {
1140                 return;
1141         }
1142
1143         if ( !path.top().get().isRoot() ) {
1144                 Selectable* selectable = Instance_getSelectable( instance );
1145                 if ( selectable != 0
1146                          && selectable->isSelected() ) {
1147                         NodeSmartReference clone( Node_Clone( path.top() ) );
1148                         if ( doMakeUnique ) {
1149                                 Map_gatherNamespaced( clone );
1150                         }
1151                         Node_getTraversable( path.parent().get() )->insert( clone );
1152                 }
1153         }
1154 }
1155 };
1156
1157 void Scene_Clone_Selected( scene::Graph& graph, bool doMakeUnique ){
1158         graph.traverse( CloneSelected( doMakeUnique ) );
1159
1160         Map_mergeClonedNames();
1161 }
1162
1163 enum ENudgeDirection
1164 {
1165         eNudgeUp = 1,
1166         eNudgeDown = 3,
1167         eNudgeLeft = 0,
1168         eNudgeRight = 2,
1169 };
1170
1171 struct AxisBase
1172 {
1173         Vector3 x;
1174         Vector3 y;
1175         Vector3 z;
1176         AxisBase( const Vector3& x_, const Vector3& y_, const Vector3& z_ )
1177                 : x( x_ ), y( y_ ), z( z_ ){
1178         }
1179 };
1180
1181 AxisBase AxisBase_forViewType( VIEWTYPE viewtype ){
1182         switch ( viewtype )
1183         {
1184         case XY:
1185                 return AxisBase( g_vector3_axis_x, g_vector3_axis_y, g_vector3_axis_z );
1186         case XZ:
1187                 return AxisBase( g_vector3_axis_x, g_vector3_axis_z, g_vector3_axis_y );
1188         case YZ:
1189                 return AxisBase( g_vector3_axis_y, g_vector3_axis_z, g_vector3_axis_x );
1190         }
1191
1192         ERROR_MESSAGE( "invalid viewtype" );
1193         return AxisBase( Vector3( 0, 0, 0 ), Vector3( 0, 0, 0 ), Vector3( 0, 0, 0 ) );
1194 }
1195
1196 Vector3 AxisBase_axisForDirection( const AxisBase& axes, ENudgeDirection direction ){
1197         switch ( direction )
1198         {
1199         case eNudgeLeft:
1200                 return vector3_negated( axes.x );
1201         case eNudgeUp:
1202                 return axes.y;
1203         case eNudgeRight:
1204                 return axes.x;
1205         case eNudgeDown:
1206                 return vector3_negated( axes.y );
1207         }
1208
1209         ERROR_MESSAGE( "invalid direction" );
1210         return Vector3( 0, 0, 0 );
1211 }
1212
1213 void NudgeSelection( ENudgeDirection direction, float fAmount, VIEWTYPE viewtype ){
1214         AxisBase axes( AxisBase_forViewType( viewtype ) );
1215         Vector3 view_direction( vector3_negated( axes.z ) );
1216         Vector3 nudge( vector3_scaled( AxisBase_axisForDirection( axes, direction ), fAmount ) );
1217         GlobalSelectionSystem().NudgeManipulator( nudge, view_direction );
1218 }
1219
1220 void Selection_Clone(){
1221         if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) {
1222                 UndoableCommand undo( "cloneSelected" );
1223
1224                 Scene_Clone_Selected( GlobalSceneGraph(), false );
1225
1226         }
1227 }
1228
1229 void Selection_Clone_MakeUnique(){
1230         if ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) {
1231                 UndoableCommand undo( "cloneSelectedMakeUnique" );
1232
1233                 Scene_Clone_Selected( GlobalSceneGraph(), true );
1234
1235         }
1236 }
1237
1238 // called when the escape key is used (either on the main window or on an inspector)
1239 void Selection_Deselect(){
1240         if ( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent ) {
1241                 if ( GlobalSelectionSystem().countSelectedComponents() != 0 ) {
1242                         GlobalSelectionSystem().setSelectedAllComponents( false );
1243                 }
1244                 else
1245                 {
1246                         SelectionSystem_DefaultMode();
1247                         ComponentModeChanged();
1248                 }
1249         }
1250         else
1251         {
1252                 if ( GlobalSelectionSystem().countSelectedComponents() != 0 ) {
1253                         GlobalSelectionSystem().setSelectedAllComponents( false );
1254                 }
1255                 else
1256                 {
1257                         GlobalSelectionSystem().setSelectedAll( false );
1258                 }
1259         }
1260 }
1261
1262
1263 void Selection_NudgeUp(){
1264         UndoableCommand undo( "nudgeSelectedUp" );
1265         NudgeSelection( eNudgeUp, GetGridSize(), GlobalXYWnd_getCurrentViewType() );
1266 }
1267
1268 void Selection_NudgeDown(){
1269         UndoableCommand undo( "nudgeSelectedDown" );
1270         NudgeSelection( eNudgeDown, GetGridSize(), GlobalXYWnd_getCurrentViewType() );
1271 }
1272
1273 void Selection_NudgeLeft(){
1274         UndoableCommand undo( "nudgeSelectedLeft" );
1275         NudgeSelection( eNudgeLeft, GetGridSize(), GlobalXYWnd_getCurrentViewType() );
1276 }
1277
1278 void Selection_NudgeRight(){
1279         UndoableCommand undo( "nudgeSelectedRight" );
1280         NudgeSelection( eNudgeRight, GetGridSize(), GlobalXYWnd_getCurrentViewType() );
1281 }
1282
1283
1284 void TranslateToolExport( const BoolImportCallback& importCallback ){
1285         importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eTranslate );
1286 }
1287
1288 void RotateToolExport( const BoolImportCallback& importCallback ){
1289         importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eRotate );
1290 }
1291
1292 void ScaleToolExport( const BoolImportCallback& importCallback ){
1293         importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eScale );
1294 }
1295
1296 void DragToolExport( const BoolImportCallback& importCallback ){
1297         importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eDrag );
1298 }
1299
1300 void ClipperToolExport( const BoolImportCallback& importCallback ){
1301         importCallback( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eClip );
1302 }
1303
1304 FreeCaller1<const BoolImportCallback&, TranslateToolExport> g_translatemode_button_caller;
1305 BoolExportCallback g_translatemode_button_callback( g_translatemode_button_caller );
1306 ToggleItem g_translatemode_button( g_translatemode_button_callback );
1307
1308 FreeCaller1<const BoolImportCallback&, RotateToolExport> g_rotatemode_button_caller;
1309 BoolExportCallback g_rotatemode_button_callback( g_rotatemode_button_caller );
1310 ToggleItem g_rotatemode_button( g_rotatemode_button_callback );
1311
1312 FreeCaller1<const BoolImportCallback&, ScaleToolExport> g_scalemode_button_caller;
1313 BoolExportCallback g_scalemode_button_callback( g_scalemode_button_caller );
1314 ToggleItem g_scalemode_button( g_scalemode_button_callback );
1315
1316 FreeCaller1<const BoolImportCallback&, DragToolExport> g_dragmode_button_caller;
1317 BoolExportCallback g_dragmode_button_callback( g_dragmode_button_caller );
1318 ToggleItem g_dragmode_button( g_dragmode_button_callback );
1319
1320 FreeCaller1<const BoolImportCallback&, ClipperToolExport> g_clipper_button_caller;
1321 BoolExportCallback g_clipper_button_callback( g_clipper_button_caller );
1322 ToggleItem g_clipper_button( g_clipper_button_callback );
1323
1324 void ToolChanged(){
1325         g_translatemode_button.update();
1326         g_rotatemode_button.update();
1327         g_scalemode_button.update();
1328         g_dragmode_button.update();
1329         g_clipper_button.update();
1330 }
1331
1332 const char* const c_ResizeMode_status = "QE4 Drag Tool: move and resize objects";
1333
1334 void DragMode(){
1335         if ( g_currentToolMode == DragMode && g_defaultToolMode != DragMode ) {
1336                 g_defaultToolMode();
1337         }
1338         else
1339         {
1340                 g_currentToolMode = DragMode;
1341                 g_currentToolModeSupportsComponentEditing = true;
1342
1343                 OnClipMode( false );
1344
1345                 Sys_Status( c_ResizeMode_status );
1346                 GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eDrag );
1347                 ToolChanged();
1348                 ModeChangeNotify();
1349         }
1350 }
1351
1352
1353 const char* const c_TranslateMode_status = "Translate Tool: translate objects and components";
1354
1355 void TranslateMode(){
1356         if ( g_currentToolMode == TranslateMode && g_defaultToolMode != TranslateMode ) {
1357                 g_defaultToolMode();
1358         }
1359         else
1360         {
1361                 g_currentToolMode = TranslateMode;
1362                 g_currentToolModeSupportsComponentEditing = true;
1363
1364                 OnClipMode( false );
1365
1366                 Sys_Status( c_TranslateMode_status );
1367                 GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eTranslate );
1368                 ToolChanged();
1369                 ModeChangeNotify();
1370         }
1371 }
1372
1373 const char* const c_RotateMode_status = "Rotate Tool: rotate objects and components";
1374
1375 void RotateMode(){
1376         if ( g_currentToolMode == RotateMode && g_defaultToolMode != RotateMode ) {
1377                 g_defaultToolMode();
1378         }
1379         else
1380         {
1381                 g_currentToolMode = RotateMode;
1382                 g_currentToolModeSupportsComponentEditing = true;
1383
1384                 OnClipMode( false );
1385
1386                 Sys_Status( c_RotateMode_status );
1387                 GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eRotate );
1388                 ToolChanged();
1389                 ModeChangeNotify();
1390         }
1391 }
1392
1393 const char* const c_ScaleMode_status = "Scale Tool: scale objects and components";
1394
1395 void ScaleMode(){
1396         if ( g_currentToolMode == ScaleMode && g_defaultToolMode != ScaleMode ) {
1397                 g_defaultToolMode();
1398         }
1399         else
1400         {
1401                 g_currentToolMode = ScaleMode;
1402                 g_currentToolModeSupportsComponentEditing = true;
1403
1404                 OnClipMode( false );
1405
1406                 Sys_Status( c_ScaleMode_status );
1407                 GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eScale );
1408                 ToolChanged();
1409                 ModeChangeNotify();
1410         }
1411 }
1412
1413
1414 const char* const c_ClipperMode_status = "Clipper Tool: apply clip planes to objects";
1415
1416
1417 void ClipperMode(){
1418         if ( g_currentToolMode == ClipperMode && g_defaultToolMode != ClipperMode ) {
1419                 g_defaultToolMode();
1420         }
1421         else
1422         {
1423                 g_currentToolMode = ClipperMode;
1424                 g_currentToolModeSupportsComponentEditing = false;
1425
1426                 SelectionSystem_DefaultMode();
1427
1428                 OnClipMode( true );
1429
1430                 Sys_Status( c_ClipperMode_status );
1431                 GlobalSelectionSystem().SetManipulatorMode( SelectionSystem::eClip );
1432                 ToolChanged();
1433                 ModeChangeNotify();
1434         }
1435 }
1436
1437
1438 void Texdef_Rotate( float angle ){
1439         StringOutputStream command;
1440         command << "brushRotateTexture -angle " << angle;
1441         UndoableCommand undo( command.c_str() );
1442         Select_RotateTexture( angle );
1443 }
1444
1445 void Texdef_RotateClockwise(){
1446         Texdef_Rotate( static_cast<float>( fabs( g_si_globals.rotate ) ) );
1447 }
1448
1449 void Texdef_RotateAntiClockwise(){
1450         Texdef_Rotate( static_cast<float>( -fabs( g_si_globals.rotate ) ) );
1451 }
1452
1453 void Texdef_Scale( float x, float y ){
1454         StringOutputStream command;
1455         command << "brushScaleTexture -x " << x << " -y " << y;
1456         UndoableCommand undo( command.c_str() );
1457         Select_ScaleTexture( x, y );
1458 }
1459
1460 void Texdef_ScaleUp(){
1461         Texdef_Scale( 0, g_si_globals.scale[1] );
1462 }
1463
1464 void Texdef_ScaleDown(){
1465         Texdef_Scale( 0, -g_si_globals.scale[1] );
1466 }
1467
1468 void Texdef_ScaleLeft(){
1469         Texdef_Scale( -g_si_globals.scale[0],0 );
1470 }
1471
1472 void Texdef_ScaleRight(){
1473         Texdef_Scale( g_si_globals.scale[0],0 );
1474 }
1475
1476 void Texdef_Shift( float x, float y ){
1477         StringOutputStream command;
1478         command << "brushShiftTexture -x " << x << " -y " << y;
1479         UndoableCommand undo( command.c_str() );
1480         Select_ShiftTexture( x, y );
1481 }
1482
1483 void Texdef_ShiftLeft(){
1484         Texdef_Shift( -g_si_globals.shift[0], 0 );
1485 }
1486
1487 void Texdef_ShiftRight(){
1488         Texdef_Shift( g_si_globals.shift[0], 0 );
1489 }
1490
1491 void Texdef_ShiftUp(){
1492         Texdef_Shift( 0, g_si_globals.shift[1] );
1493 }
1494
1495 void Texdef_ShiftDown(){
1496         Texdef_Shift( 0, -g_si_globals.shift[1] );
1497 }
1498
1499
1500
1501 class SnappableSnapToGridSelected : public scene::Graph::Walker
1502 {
1503 float m_snap;
1504 public:
1505 SnappableSnapToGridSelected( float snap )
1506         : m_snap( snap ){
1507 }
1508 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1509         if ( path.top().get().visible() ) {
1510                 Snappable* snappable = Node_getSnappable( path.top() );
1511                 if ( snappable != 0
1512                          && Instance_getSelectable( instance )->isSelected() ) {
1513                         snappable->snapto( m_snap );
1514                 }
1515         }
1516         return true;
1517 }
1518 };
1519
1520 void Scene_SnapToGrid_Selected( scene::Graph& graph, float snap ){
1521         graph.traverse( SnappableSnapToGridSelected( snap ) );
1522 }
1523
1524 class ComponentSnappableSnapToGridSelected : public scene::Graph::Walker
1525 {
1526 float m_snap;
1527 public:
1528 ComponentSnappableSnapToGridSelected( float snap )
1529         : m_snap( snap ){
1530 }
1531 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1532         if ( path.top().get().visible() ) {
1533                 ComponentSnappable* componentSnappable = Instance_getComponentSnappable( instance );
1534                 if ( componentSnappable != 0
1535                          && Instance_getSelectable( instance )->isSelected() ) {
1536                         componentSnappable->snapComponents( m_snap );
1537                 }
1538         }
1539         return true;
1540 }
1541 };
1542
1543 void Scene_SnapToGrid_Component_Selected( scene::Graph& graph, float snap ){
1544         graph.traverse( ComponentSnappableSnapToGridSelected( snap ) );
1545 }
1546
1547 void Selection_SnapToGrid(){
1548         StringOutputStream command;
1549         command << "snapSelected -grid " << GetGridSize();
1550         UndoableCommand undo( command.c_str() );
1551
1552         if ( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent ) {
1553                 Scene_SnapToGrid_Component_Selected( GlobalSceneGraph(), GetGridSize() );
1554         }
1555         else
1556         {
1557                 Scene_SnapToGrid_Selected( GlobalSceneGraph(), GetGridSize() );
1558         }
1559 }
1560
1561
1562 static gint qe_every_second( gpointer data ){
1563         GdkModifierType mask;
1564
1565         gdk_window_get_pointer( 0, 0, 0, &mask );
1566
1567         if ( ( mask & ( GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK ) ) == 0 ) {
1568                 QE_CheckAutoSave();
1569         }
1570
1571         return TRUE;
1572 }
1573
1574 guint s_qe_every_second_id = 0;
1575
1576 void EverySecondTimer_enable(){
1577         if ( s_qe_every_second_id == 0 ) {
1578                 s_qe_every_second_id = gtk_timeout_add( 1000, qe_every_second, 0 );
1579         }
1580 }
1581
1582 void EverySecondTimer_disable(){
1583         if ( s_qe_every_second_id != 0 ) {
1584                 gtk_timeout_remove( s_qe_every_second_id );
1585                 s_qe_every_second_id = 0;
1586         }
1587 }
1588
1589 gint window_realize_remove_decoration( GtkWidget* widget, gpointer data ){
1590         gdk_window_set_decorations( widget->window, (GdkWMDecoration)( GDK_DECOR_ALL | GDK_DECOR_MENU | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE ) );
1591         return FALSE;
1592 }
1593
1594 class WaitDialog
1595 {
1596 public:
1597 GtkWindow* m_window;
1598 GtkLabel* m_label;
1599 };
1600
1601 WaitDialog create_wait_dialog( const char* title, const char* text ){
1602         WaitDialog dialog;
1603
1604         dialog.m_window = create_floating_window( title, MainFrame_getWindow() );
1605         gtk_window_set_resizable( dialog.m_window, FALSE );
1606         gtk_container_set_border_width( GTK_CONTAINER( dialog.m_window ), 0 );
1607         gtk_window_set_position( dialog.m_window, GTK_WIN_POS_CENTER_ON_PARENT );
1608
1609         g_signal_connect( G_OBJECT( dialog.m_window ), "realize", G_CALLBACK( window_realize_remove_decoration ), 0 );
1610
1611         {
1612                 dialog.m_label = GTK_LABEL( gtk_label_new( text ) );
1613                 gtk_misc_set_alignment( GTK_MISC( dialog.m_label ), 0.0, 0.5 );
1614                 gtk_label_set_justify( dialog.m_label, GTK_JUSTIFY_LEFT );
1615                 gtk_widget_show( GTK_WIDGET( dialog.m_label ) );
1616                 gtk_widget_set_size_request( GTK_WIDGET( dialog.m_label ), 200, -1 );
1617
1618                 gtk_container_add( GTK_CONTAINER( dialog.m_window ), GTK_WIDGET( dialog.m_label ) );
1619         }
1620         return dialog;
1621 }
1622
1623 namespace
1624 {
1625 clock_t g_lastRedrawTime = 0;
1626 const clock_t c_redrawInterval = clock_t( CLOCKS_PER_SEC / 10 );
1627
1628 bool redrawRequired(){
1629         clock_t currentTime = std::clock();
1630         if ( currentTime - g_lastRedrawTime >= c_redrawInterval ) {
1631                 g_lastRedrawTime = currentTime;
1632                 return true;
1633         }
1634         return false;
1635 }
1636 }
1637
1638 bool MainFrame_isActiveApp(){
1639         GList* list = gtk_window_list_toplevels();
1640         for ( GList* i = list; i != 0; i = g_list_next( i ) )
1641         {
1642                 if ( gtk_window_is_active( GTK_WINDOW( i->data ) ) ) {
1643                         return true;
1644                 }
1645         }
1646         return false;
1647 }
1648
1649 typedef std::list<CopiedString> StringStack;
1650 StringStack g_wait_stack;
1651 WaitDialog g_wait;
1652
1653 bool ScreenUpdates_Enabled(){
1654         return g_wait_stack.empty();
1655 }
1656
1657 void ScreenUpdates_process(){
1658         if ( redrawRequired() && GTK_WIDGET_VISIBLE( g_wait.m_window ) ) {
1659                 process_gui();
1660         }
1661 }
1662
1663
1664 void ScreenUpdates_Disable( const char* message, const char* title ){
1665         if ( g_wait_stack.empty() ) {
1666                 EverySecondTimer_disable();
1667
1668                 process_gui();
1669
1670                 bool isActiveApp = MainFrame_isActiveApp();
1671
1672                 g_wait = create_wait_dialog( title, message );
1673                 gtk_grab_add( GTK_WIDGET( g_wait.m_window ) );
1674
1675                 if ( isActiveApp ) {
1676                         gtk_widget_show( GTK_WIDGET( g_wait.m_window ) );
1677                         ScreenUpdates_process();
1678                 }
1679         }
1680         else if ( GTK_WIDGET_VISIBLE( g_wait.m_window ) ) {
1681                 gtk_label_set_text( g_wait.m_label, message );
1682                 ScreenUpdates_process();
1683         }
1684         g_wait_stack.push_back( message );
1685 }
1686
1687 void ScreenUpdates_Enable(){
1688         ASSERT_MESSAGE( !ScreenUpdates_Enabled(), "screen updates already enabled" );
1689         g_wait_stack.pop_back();
1690         if ( g_wait_stack.empty() ) {
1691                 EverySecondTimer_enable();
1692
1693                 gtk_grab_remove( GTK_WIDGET( g_wait.m_window ) );
1694                 destroy_floating_window( g_wait.m_window );
1695                 g_wait.m_window = 0;
1696
1697         }
1698         else if ( GTK_WIDGET_VISIBLE( g_wait.m_window ) ) {
1699                 gtk_label_set_text( g_wait.m_label, g_wait_stack.back().c_str() );
1700                 ScreenUpdates_process();
1701         }
1702 }
1703
1704
1705
1706 void GlobalCamera_UpdateWindow(){
1707         if ( g_pParentWnd != 0 ) {
1708                 CamWnd_Update( *g_pParentWnd->GetCamWnd() );
1709         }
1710 }
1711
1712 void XY_UpdateWindow( MainFrame& mainframe ){
1713         if ( mainframe.GetXYWnd() != 0 ) {
1714                 XYWnd_Update( *mainframe.GetXYWnd() );
1715         }
1716 }
1717
1718 void XZ_UpdateWindow( MainFrame& mainframe ){
1719         if ( mainframe.GetXZWnd() != 0 ) {
1720                 XYWnd_Update( *mainframe.GetXZWnd() );
1721         }
1722 }
1723
1724 void YZ_UpdateWindow( MainFrame& mainframe ){
1725         if ( mainframe.GetYZWnd() != 0 ) {
1726                 XYWnd_Update( *mainframe.GetYZWnd() );
1727         }
1728 }
1729
1730 void XY_UpdateAllWindows( MainFrame& mainframe ){
1731         XY_UpdateWindow( mainframe );
1732         XZ_UpdateWindow( mainframe );
1733         YZ_UpdateWindow( mainframe );
1734 }
1735
1736 void XY_UpdateAllWindows(){
1737         if ( g_pParentWnd != 0 ) {
1738                 XY_UpdateAllWindows( *g_pParentWnd );
1739         }
1740 }
1741
1742 void UpdateAllWindows(){
1743         GlobalCamera_UpdateWindow();
1744         XY_UpdateAllWindows();
1745 }
1746
1747
1748 void ModeChangeNotify(){
1749         SceneChangeNotify();
1750 }
1751
1752 void ClipperChangeNotify(){
1753         GlobalCamera_UpdateWindow();
1754         XY_UpdateAllWindows();
1755 }
1756
1757
1758 LatchedInt g_Layout_viewStyle( 0, "Window Layout" );
1759 LatchedBool g_Layout_enableDetachableMenus( true, "Detachable Menus" );
1760 LatchedBool g_Layout_enablePatchToolbar( true, "Patch Toolbar" );
1761 LatchedBool g_Layout_enablePluginToolbar( true, "Plugin Toolbar" );
1762
1763
1764
1765 GtkMenuItem* create_file_menu(){
1766         // File menu
1767         GtkMenuItem* file_menu_item = new_sub_menu_item_with_mnemonic( "_File" );
1768         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( file_menu_item ) );
1769         if ( g_Layout_enableDetachableMenus.m_value ) {
1770                 menu_tearoff( menu );
1771         }
1772
1773         create_menu_item_with_mnemonic( menu, "_New Map", "NewMap" );
1774         menu_separator( menu );
1775
1776
1777         create_menu_item_with_mnemonic( menu, "_Open...", "OpenMap" );
1778
1779         create_menu_item_with_mnemonic( menu, "_Import...", "ImportMap" );
1780         create_menu_item_with_mnemonic( menu, "_Save", "SaveMap" );
1781         create_menu_item_with_mnemonic( menu, "Save _as...", "SaveMapAs" );
1782         create_menu_item_with_mnemonic( menu, "Save s_elected...", "SaveSelected" );
1783         menu_separator( menu );
1784         create_menu_item_with_mnemonic( menu, "Save re_gion...", "SaveRegion" );
1785         menu_separator( menu );
1786         create_menu_item_with_mnemonic( menu, "_Refresh models", "RefreshReferences" );
1787         menu_separator( menu );
1788         create_menu_item_with_mnemonic( menu, "Pro_ject settings...", "ProjectSettings" );
1789         menu_separator( menu );
1790         create_menu_item_with_mnemonic( menu, "_Pointfile...", "TogglePointfile" );
1791         menu_separator( menu );
1792         MRU_constructMenu( menu );
1793         menu_separator( menu );
1794         create_menu_item_with_mnemonic( menu, "Check for NetRadiant update (web)", "CheckForUpdate" ); // FIXME
1795         create_menu_item_with_mnemonic( menu, "E_xit", "Exit" );
1796
1797         return file_menu_item;
1798 }
1799
1800 GtkMenuItem* create_edit_menu(){
1801         // Edit menu
1802         GtkMenuItem* edit_menu_item = new_sub_menu_item_with_mnemonic( "_Edit" );
1803         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( edit_menu_item ) );
1804         if ( g_Layout_enableDetachableMenus.m_value ) {
1805                 menu_tearoff( menu );
1806         }
1807         create_menu_item_with_mnemonic( menu, "_Undo", "Undo" );
1808         create_menu_item_with_mnemonic( menu, "_Redo", "Redo" );
1809         menu_separator( menu );
1810         create_menu_item_with_mnemonic( menu, "_Copy", "Copy" );
1811         create_menu_item_with_mnemonic( menu, "_Paste", "Paste" );
1812         create_menu_item_with_mnemonic( menu, "P_aste To Camera", "PasteToCamera" );
1813         menu_separator( menu );
1814         create_menu_item_with_mnemonic( menu, "_Duplicate", "CloneSelection" );
1815         create_menu_item_with_mnemonic( menu, "Duplicate, make uni_que", "CloneSelectionAndMakeUnique" );
1816         create_menu_item_with_mnemonic( menu, "D_elete", "DeleteSelection" );
1817         menu_separator( menu );
1818         create_menu_item_with_mnemonic( menu, "Pa_rent", "ParentSelection" );
1819         menu_separator( menu );
1820         create_menu_item_with_mnemonic( menu, "C_lear Selection", "UnSelectSelection" );
1821         create_menu_item_with_mnemonic( menu, "_Invert Selection", "InvertSelection" );
1822         create_menu_item_with_mnemonic( menu, "Select i_nside", "SelectInside" );
1823         create_menu_item_with_mnemonic( menu, "Select _touching", "SelectTouching" );
1824
1825         GtkMenu* convert_menu = create_sub_menu_with_mnemonic( menu, "E_xpand Selection" );
1826         if ( g_Layout_enableDetachableMenus.m_value ) {
1827                 menu_tearoff( convert_menu );
1828         }
1829         create_menu_item_with_mnemonic( convert_menu, "To Whole _Entities", "ExpandSelectionToEntities" );
1830
1831         menu_separator( menu );
1832         create_menu_item_with_mnemonic( menu, "Pre_ferences...", "Preferences" );
1833
1834         return edit_menu_item;
1835 }
1836
1837 void fill_view_xy_top_menu( GtkMenu* menu ){
1838         create_check_menu_item_with_mnemonic( menu, "XY (Top) View", "ToggleView" );
1839 }
1840
1841
1842 void fill_view_yz_side_menu( GtkMenu* menu ){
1843         create_check_menu_item_with_mnemonic( menu, "YZ (Side) View", "ToggleSideView" );
1844 }
1845
1846
1847 void fill_view_xz_front_menu( GtkMenu* menu ){
1848         create_check_menu_item_with_mnemonic( menu, "XZ (Front) View", "ToggleFrontView" );
1849 }
1850
1851
1852 GtkWidget* g_toggle_z_item = 0;
1853 GtkWidget* g_toggle_console_item = 0;
1854 GtkWidget* g_toggle_entity_item = 0;
1855 GtkWidget* g_toggle_entitylist_item = 0;
1856
1857 GtkMenuItem* create_view_menu( MainFrame::EViewStyle style ){
1858         // View menu
1859         GtkMenuItem* view_menu_item = new_sub_menu_item_with_mnemonic( "Vie_w" );
1860         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( view_menu_item ) );
1861         if ( g_Layout_enableDetachableMenus.m_value ) {
1862                 menu_tearoff( menu );
1863         }
1864
1865         if ( style == MainFrame::eFloating ) {
1866                 fill_view_camera_menu( menu );
1867                 fill_view_xy_top_menu( menu );
1868                 fill_view_yz_side_menu( menu );
1869                 fill_view_xz_front_menu( menu );
1870         }
1871         if ( style == MainFrame::eFloating || style == MainFrame::eSplit ) {
1872                 create_menu_item_with_mnemonic( menu, "Console View", "ToggleConsole" );
1873                 create_menu_item_with_mnemonic( menu, "Texture Browser", "ToggleTextures" );
1874                 create_menu_item_with_mnemonic( menu, "Entity Inspector", "ToggleEntityInspector" );
1875         }
1876         else
1877         {
1878                 create_menu_item_with_mnemonic( menu, "Entity Inspector", "ViewEntityInfo" );
1879         }
1880         create_menu_item_with_mnemonic( menu, "_Surface Inspector", "SurfaceInspector" );
1881         create_menu_item_with_mnemonic( menu, "Entity List", "EntityList" );
1882
1883         menu_separator( menu );
1884         {
1885                 GtkMenu* camera_menu = create_sub_menu_with_mnemonic( menu, "Camera" );
1886                 if ( g_Layout_enableDetachableMenus.m_value ) {
1887                         menu_tearoff( camera_menu );
1888                 }
1889                 create_menu_item_with_mnemonic( camera_menu, "_Center", "CenterView" );
1890                 create_menu_item_with_mnemonic( camera_menu, "_Up Floor", "UpFloor" );
1891                 create_menu_item_with_mnemonic( camera_menu, "_Down Floor", "DownFloor" );
1892                 menu_separator( camera_menu );
1893                 create_menu_item_with_mnemonic( camera_menu, "Far Clip Plane In", "CubicClipZoomIn" );
1894                 create_menu_item_with_mnemonic( camera_menu, "Far Clip Plane Out", "CubicClipZoomOut" );
1895                 menu_separator( camera_menu );
1896                 create_menu_item_with_mnemonic( camera_menu, "Next leak spot", "NextLeakSpot" );
1897                 create_menu_item_with_mnemonic( camera_menu, "Previous leak spot", "PrevLeakSpot" );
1898                 menu_separator( camera_menu );
1899                 create_menu_item_with_mnemonic( camera_menu, "Look Through Selected", "LookThroughSelected" );
1900                 create_menu_item_with_mnemonic( camera_menu, "Look Through Camera", "LookThroughCamera" );
1901         }
1902         menu_separator( menu );
1903         {
1904                 GtkMenu* orthographic_menu = create_sub_menu_with_mnemonic( menu, "Orthographic" );
1905                 if ( g_Layout_enableDetachableMenus.m_value ) {
1906                         menu_tearoff( orthographic_menu );
1907                 }
1908                 if ( style == MainFrame::eRegular || style == MainFrame::eRegularLeft || style == MainFrame::eFloating ) {
1909                         create_menu_item_with_mnemonic( orthographic_menu, "_Next (XY, YZ, XY)", "NextView" );
1910                         create_menu_item_with_mnemonic( orthographic_menu, "XY (Top)", "ViewTop" );
1911                         create_menu_item_with_mnemonic( orthographic_menu, "YZ", "ViewSide" );
1912                         create_menu_item_with_mnemonic( orthographic_menu, "XZ", "ViewFront" );
1913                         menu_separator( orthographic_menu );
1914                 }
1915
1916                 create_menu_item_with_mnemonic( orthographic_menu, "_XY 100%", "Zoom100" );
1917                 create_menu_item_with_mnemonic( orthographic_menu, "XY Zoom _In", "ZoomIn" );
1918                 create_menu_item_with_mnemonic( orthographic_menu, "XY Zoom _Out", "ZoomOut" );
1919         }
1920
1921         menu_separator( menu );
1922
1923         {
1924                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Show" );
1925                 if ( g_Layout_enableDetachableMenus.m_value ) {
1926                         menu_tearoff( menu_in_menu );
1927                 }
1928                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show _Angles", "ShowAngles" );
1929                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show _Names", "ShowNames" );
1930                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show Blocks", "ShowBlocks" );
1931                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show C_oordinates", "ShowCoordinates" );
1932                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show Window Outline", "ShowWindowOutline" );
1933                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show Axes", "ShowAxes" );
1934                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show Workzone", "ShowWorkzone" );
1935                 create_check_menu_item_with_mnemonic( menu_in_menu, "Show Stats", "ShowStats" );
1936         }
1937
1938         {
1939                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Filter" );
1940                 if ( g_Layout_enableDetachableMenus.m_value ) {
1941                         menu_tearoff( menu_in_menu );
1942                 }
1943                 Filters_constructMenu( menu_in_menu );
1944         }
1945         menu_separator( menu );
1946         {
1947                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Hide/Show" );
1948                 if ( g_Layout_enableDetachableMenus.m_value ) {
1949                         menu_tearoff( menu_in_menu );
1950                 }
1951                 create_menu_item_with_mnemonic( menu_in_menu, "Hide Selected", "HideSelected" );
1952                 create_menu_item_with_mnemonic( menu_in_menu, "Show Hidden", "ShowHidden" );
1953         }
1954         menu_separator( menu );
1955         {
1956                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Region" );
1957                 if ( g_Layout_enableDetachableMenus.m_value ) {
1958                         menu_tearoff( menu_in_menu );
1959                 }
1960                 create_menu_item_with_mnemonic( menu_in_menu, "_Off", "RegionOff" );
1961                 create_menu_item_with_mnemonic( menu_in_menu, "_Set XY", "RegionSetXY" );
1962                 create_menu_item_with_mnemonic( menu_in_menu, "Set _Brush", "RegionSetBrush" );
1963                 create_menu_item_with_mnemonic( menu_in_menu, "Set Se_lected Brushes", "RegionSetSelection" );
1964         }
1965
1966         command_connect_accelerator( "CenterXYView" );
1967
1968         return view_menu_item;
1969 }
1970
1971 GtkMenuItem* create_selection_menu(){
1972         // Selection menu
1973         GtkMenuItem* selection_menu_item = new_sub_menu_item_with_mnemonic( "M_odify" );
1974         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( selection_menu_item ) );
1975         if ( g_Layout_enableDetachableMenus.m_value ) {
1976                 menu_tearoff( menu );
1977         }
1978
1979         {
1980                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Components" );
1981                 if ( g_Layout_enableDetachableMenus.m_value ) {
1982                         menu_tearoff( menu_in_menu );
1983                 }
1984                 create_check_menu_item_with_mnemonic( menu_in_menu, "_Edges", "DragEdges" );
1985                 create_check_menu_item_with_mnemonic( menu_in_menu, "_Vertices", "DragVertices" );
1986                 create_check_menu_item_with_mnemonic( menu_in_menu, "_Faces", "DragFaces" );
1987         }
1988
1989         menu_separator( menu );
1990
1991         {
1992                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Nudge" );
1993                 if ( g_Layout_enableDetachableMenus.m_value ) {
1994                         menu_tearoff( menu_in_menu );
1995                 }
1996                 create_menu_item_with_mnemonic( menu_in_menu, "Nudge Left", "SelectNudgeLeft" );
1997                 create_menu_item_with_mnemonic( menu_in_menu, "Nudge Right", "SelectNudgeRight" );
1998                 create_menu_item_with_mnemonic( menu_in_menu, "Nudge Up", "SelectNudgeUp" );
1999                 create_menu_item_with_mnemonic( menu_in_menu, "Nudge Down", "SelectNudgeDown" );
2000         }
2001         {
2002                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Rotate" );
2003                 if ( g_Layout_enableDetachableMenus.m_value ) {
2004                         menu_tearoff( menu_in_menu );
2005                 }
2006                 create_menu_item_with_mnemonic( menu_in_menu, "Rotate X", "RotateSelectionX" );
2007                 create_menu_item_with_mnemonic( menu_in_menu, "Rotate Y", "RotateSelectionY" );
2008                 create_menu_item_with_mnemonic( menu_in_menu, "Rotate Z", "RotateSelectionZ" );
2009         }
2010         {
2011                 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Flip" );
2012                 if ( g_Layout_enableDetachableMenus.m_value ) {
2013                         menu_tearoff( menu_in_menu );
2014                 }
2015                 create_menu_item_with_mnemonic( menu_in_menu, "Flip _X", "MirrorSelectionX" );
2016                 create_menu_item_with_mnemonic( menu_in_menu, "Flip _Y", "MirrorSelectionY" );
2017                 create_menu_item_with_mnemonic( menu_in_menu, "Flip _Z", "MirrorSelectionZ" );
2018         }
2019         menu_separator( menu );
2020         create_menu_item_with_mnemonic( menu, "Arbitrary rotation...", "ArbitraryRotation" );
2021         create_menu_item_with_mnemonic( menu, "Arbitrary scale...", "ArbitraryScale" );
2022
2023         return selection_menu_item;
2024 }
2025
2026 GtkMenuItem* create_bsp_menu(){
2027         // BSP menu
2028         GtkMenuItem* bsp_menu_item = new_sub_menu_item_with_mnemonic( "_Build" );
2029         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( bsp_menu_item ) );
2030
2031         if ( g_Layout_enableDetachableMenus.m_value ) {
2032                 menu_tearoff( menu );
2033         }
2034
2035         create_menu_item_with_mnemonic( menu, "Customize...", "BuildMenuCustomize" );
2036
2037         menu_separator( menu );
2038
2039         Build_constructMenu( menu );
2040
2041         g_bsp_menu = menu;
2042
2043         return bsp_menu_item;
2044 }
2045
2046 GtkMenuItem* create_grid_menu(){
2047         // Grid menu
2048         GtkMenuItem* grid_menu_item = new_sub_menu_item_with_mnemonic( "_Grid" );
2049         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( grid_menu_item ) );
2050         if ( g_Layout_enableDetachableMenus.m_value ) {
2051                 menu_tearoff( menu );
2052         }
2053
2054         Grid_constructMenu( menu );
2055
2056         return grid_menu_item;
2057 }
2058
2059 GtkMenuItem* create_misc_menu(){
2060         // Misc menu
2061         GtkMenuItem* misc_menu_item = new_sub_menu_item_with_mnemonic( "M_isc" );
2062         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( misc_menu_item ) );
2063         if ( g_Layout_enableDetachableMenus.m_value ) {
2064                 menu_tearoff( menu );
2065         }
2066
2067         gtk_container_add( GTK_CONTAINER( menu ), GTK_WIDGET( create_colours_menu() ) );
2068
2069         create_menu_item_with_mnemonic( menu, "Find brush...", "FindBrush" );
2070         create_menu_item_with_mnemonic( menu, "Map Info...", "MapInfo" );
2071         // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394
2072         create_menu_item_with_mnemonic( menu, "_Background select", FreeCaller<WXY_BackgroundSelect>() );
2073         return misc_menu_item;
2074 }
2075
2076 GtkMenuItem* create_entity_menu(){
2077         // Brush menu
2078         GtkMenuItem* entity_menu_item = new_sub_menu_item_with_mnemonic( "E_ntity" );
2079         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( entity_menu_item ) );
2080         if ( g_Layout_enableDetachableMenus.m_value ) {
2081                 menu_tearoff( menu );
2082         }
2083
2084         Entity_constructMenu( menu );
2085
2086         return entity_menu_item;
2087 }
2088
2089 GtkMenuItem* create_brush_menu(){
2090         // Brush menu
2091         GtkMenuItem* brush_menu_item = new_sub_menu_item_with_mnemonic( "B_rush" );
2092         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( brush_menu_item ) );
2093         if ( g_Layout_enableDetachableMenus.m_value ) {
2094                 menu_tearoff( menu );
2095         }
2096
2097         Brush_constructMenu( menu );
2098
2099         return brush_menu_item;
2100 }
2101
2102 GtkMenuItem* create_patch_menu(){
2103         // Curve menu
2104         GtkMenuItem* patch_menu_item = new_sub_menu_item_with_mnemonic( "_Curve" );
2105         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( patch_menu_item ) );
2106         if ( g_Layout_enableDetachableMenus.m_value ) {
2107                 menu_tearoff( menu );
2108         }
2109
2110         Patch_constructMenu( menu );
2111
2112         return patch_menu_item;
2113 }
2114
2115 GtkMenuItem* create_help_menu(){
2116         // Help menu
2117         GtkMenuItem* help_menu_item = new_sub_menu_item_with_mnemonic( "_Help" );
2118         GtkMenu* menu = GTK_MENU( gtk_menu_item_get_submenu( help_menu_item ) );
2119         if ( g_Layout_enableDetachableMenus.m_value ) {
2120                 menu_tearoff( menu );
2121         }
2122
2123         create_menu_item_with_mnemonic( menu, "Manual", "OpenManual" );
2124
2125         // this creates all the per-game drop downs for the game pack helps
2126         // it will take care of hooking the Sys_OpenURL calls etc.
2127         create_game_help_menu( menu );
2128
2129         create_menu_item_with_mnemonic( menu, "Bug report", FreeCaller<OpenBugReportURL>() );
2130         create_menu_item_with_mnemonic( menu, "Shortcuts list", FreeCaller<DoCommandListDlg>() );
2131         create_menu_item_with_mnemonic( menu, "_About", FreeCaller<DoAbout>() );
2132
2133         return help_menu_item;
2134 }
2135
2136 GtkMenuBar* create_main_menu( MainFrame::EViewStyle style ){
2137         GtkMenuBar* menu_bar = GTK_MENU_BAR( gtk_menu_bar_new() );
2138         gtk_widget_show( GTK_WIDGET( menu_bar ) );
2139
2140         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_file_menu() ) );
2141         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_edit_menu() ) );
2142         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_view_menu( style ) ) );
2143         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_selection_menu() ) );
2144         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_bsp_menu() ) );
2145         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_grid_menu() ) );
2146         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_misc_menu() ) );
2147         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_entity_menu() ) );
2148         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_brush_menu() ) );
2149         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_patch_menu() ) );
2150         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_plugins_menu() ) );
2151         gtk_container_add( GTK_CONTAINER( menu_bar ), GTK_WIDGET( create_help_menu() ) );
2152
2153         return menu_bar;
2154 }
2155
2156
2157 void PatchInspector_registerShortcuts(){
2158         command_connect_accelerator( "PatchInspector" );
2159 }
2160
2161 void Patch_registerShortcuts(){
2162         command_connect_accelerator( "InvertCurveTextureX" );
2163         command_connect_accelerator( "InvertCurveTextureY" );
2164         command_connect_accelerator( "PatchInsertInsertColumn" );
2165         command_connect_accelerator( "PatchInsertInsertRow" );
2166         command_connect_accelerator( "PatchDeleteLastColumn" );
2167         command_connect_accelerator( "PatchDeleteLastRow" );
2168         command_connect_accelerator( "NaturalizePatch" );
2169 }
2170
2171 void Manipulators_registerShortcuts(){
2172         toggle_add_accelerator( "MouseRotate" );
2173         toggle_add_accelerator( "MouseTranslate" );
2174         toggle_add_accelerator( "MouseScale" );
2175         toggle_add_accelerator( "MouseDrag" );
2176         toggle_add_accelerator( "ToggleClipper" );
2177 }
2178
2179 void TexdefNudge_registerShortcuts(){
2180         command_connect_accelerator( "TexRotateClock" );
2181         command_connect_accelerator( "TexRotateCounter" );
2182         command_connect_accelerator( "TexScaleUp" );
2183         command_connect_accelerator( "TexScaleDown" );
2184         command_connect_accelerator( "TexScaleLeft" );
2185         command_connect_accelerator( "TexScaleRight" );
2186         command_connect_accelerator( "TexShiftUp" );
2187         command_connect_accelerator( "TexShiftDown" );
2188         command_connect_accelerator( "TexShiftLeft" );
2189         command_connect_accelerator( "TexShiftRight" );
2190 }
2191
2192 void SelectNudge_registerShortcuts(){
2193         command_connect_accelerator( "MoveSelectionDOWN" );
2194         command_connect_accelerator( "MoveSelectionUP" );
2195 }
2196
2197 void SnapToGrid_registerShortcuts(){
2198         command_connect_accelerator( "SnapToGrid" );
2199 }
2200
2201 void SelectByType_registerShortcuts(){
2202         command_connect_accelerator( "SelectAllOfType" );
2203 }
2204
2205 void SurfaceInspector_registerShortcuts(){
2206         command_connect_accelerator( "FitTexture" );
2207 }
2208
2209
2210 void register_shortcuts(){
2211         PatchInspector_registerShortcuts();
2212         Patch_registerShortcuts();
2213         Grid_registerShortcuts();
2214         XYWnd_registerShortcuts();
2215         CamWnd_registerShortcuts();
2216         Manipulators_registerShortcuts();
2217         SurfaceInspector_registerShortcuts();
2218         TexdefNudge_registerShortcuts();
2219         SelectNudge_registerShortcuts();
2220         SnapToGrid_registerShortcuts();
2221         SelectByType_registerShortcuts();
2222 }
2223
2224 void File_constructToolbar( GtkToolbar* toolbar ){
2225         toolbar_append_button( toolbar, "Open an existing map (CTRL + O)", "file_open.png", "OpenMap" );
2226         toolbar_append_button( toolbar, "Save the active map (CTRL + S)", "file_save.png", "SaveMap" );
2227 }
2228
2229 void UndoRedo_constructToolbar( GtkToolbar* toolbar ){
2230         toolbar_append_button( toolbar, "Undo (CTRL + Z)", "undo.png", "Undo" );
2231         toolbar_append_button( toolbar, "Redo (CTRL + Y)", "redo.png", "Redo" );
2232 }
2233
2234 void RotateFlip_constructToolbar( GtkToolbar* toolbar ){
2235         toolbar_append_button( toolbar, "x-axis Flip", "brush_flipx.png", "MirrorSelectionX" );
2236         toolbar_append_button( toolbar, "x-axis Rotate", "brush_rotatex.png", "RotateSelectionX" );
2237         toolbar_append_button( toolbar, "y-axis Flip", "brush_flipy.png", "MirrorSelectionY" );
2238         toolbar_append_button( toolbar, "y-axis Rotate", "brush_rotatey.png", "RotateSelectionY" );
2239         toolbar_append_button( toolbar, "z-axis Flip", "brush_flipz.png", "MirrorSelectionZ" );
2240         toolbar_append_button( toolbar, "z-axis Rotate", "brush_rotatez.png", "RotateSelectionZ" );
2241 }
2242
2243 void Select_constructToolbar( GtkToolbar* toolbar ){
2244         toolbar_append_button( toolbar, "Select touching", "selection_selecttouching.png", "SelectTouching" );
2245         toolbar_append_button( toolbar, "Select inside", "selection_selectinside.png", "SelectInside" );
2246 }
2247
2248 void CSG_constructToolbar( GtkToolbar* toolbar ){
2249         toolbar_append_button( toolbar, "CSG Subtract (SHIFT + U)", "selection_csgsubtract.png", "CSGSubtract" );
2250         toolbar_append_button( toolbar, "CSG Merge (CTRL + U)", "selection_csgmerge.png", "CSGMerge" );
2251         toolbar_append_button( toolbar, "Hollow", "selection_makehollow.png", "CSGHollow" );
2252 }
2253
2254 void ComponentModes_constructToolbar( GtkToolbar* toolbar ){
2255         toolbar_append_toggle_button( toolbar, "Select Vertices (V)", "modify_vertices.png", "DragVertices" );
2256         toolbar_append_toggle_button( toolbar, "Select Edges (E)", "modify_edges.png", "DragEdges" );
2257         toolbar_append_toggle_button( toolbar, "Select Faces (F)", "modify_faces.png", "DragFaces" );
2258 }
2259
2260 void Clipper_constructToolbar( GtkToolbar* toolbar ){
2261
2262         toolbar_append_toggle_button( toolbar, "Clipper (X)", "view_clipper.png", "ToggleClipper" );
2263 }
2264
2265 void XYWnd_constructToolbar( GtkToolbar* toolbar ){
2266         toolbar_append_button( toolbar, "Change views", "view_change.png", "NextView" );
2267 }
2268
2269 void Manipulators_constructToolbar( GtkToolbar* toolbar ){
2270         toolbar_append_toggle_button( toolbar, "Translate (W)", "select_mousetranslate.png", "MouseTranslate" );
2271         toolbar_append_toggle_button( toolbar, "Rotate (R)", "select_mouserotate.png", "MouseRotate" );
2272         toolbar_append_toggle_button( toolbar, "Scale", "select_mousescale.png", "MouseScale" );
2273         toolbar_append_toggle_button( toolbar, "Resize (Q)", "select_mouseresize.png", "MouseDrag" );
2274
2275         Clipper_constructToolbar( toolbar );
2276 }
2277
2278 GtkToolbar* create_main_toolbar( MainFrame::EViewStyle style ){
2279         GtkToolbar* toolbar = GTK_TOOLBAR( gtk_toolbar_new() );
2280         gtk_toolbar_set_orientation( toolbar, GTK_ORIENTATION_HORIZONTAL );
2281         gtk_toolbar_set_style( toolbar, GTK_TOOLBAR_ICONS );
2282
2283         gtk_widget_show( GTK_WIDGET( toolbar ) );
2284
2285         File_constructToolbar( toolbar );
2286
2287         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2288
2289         UndoRedo_constructToolbar( toolbar );
2290
2291         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2292
2293         RotateFlip_constructToolbar( toolbar );
2294
2295         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2296
2297         Select_constructToolbar( toolbar );
2298
2299         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2300
2301         CSG_constructToolbar( toolbar );
2302
2303         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2304
2305         ComponentModes_constructToolbar( toolbar );
2306
2307         if ( style == MainFrame::eRegular || style == MainFrame::eRegularLeft || style == MainFrame::eFloating ) {
2308                 gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2309
2310                 XYWnd_constructToolbar( toolbar );
2311         }
2312
2313         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2314
2315         CamWnd_constructToolbar( toolbar );
2316
2317         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2318
2319         Manipulators_constructToolbar( toolbar );
2320
2321         if ( g_Layout_enablePatchToolbar.m_value ) {
2322                 gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2323
2324                 Patch_constructToolbar( toolbar );
2325         }
2326
2327         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2328
2329         toolbar_append_toggle_button( toolbar, "Texture Lock (SHIFT +T)", "texture_lock.png", "TogTexLock" );
2330
2331         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2332
2333         GtkButton* g_view_entities_button = toolbar_append_button( toolbar, "Entities (N)", "entities.png", "ToggleEntityInspector" );
2334         GtkButton* g_view_console_button = toolbar_append_button( toolbar, "Console (O)", "console.png", "ToggleConsole" );
2335         GtkButton* g_view_textures_button = toolbar_append_button( toolbar, "Texture Browser (T)", "texture_browser.png", "ToggleTextures" );
2336         // TODO: call light inspector
2337
2338         gtk_toolbar_append_space( GTK_TOOLBAR( toolbar ) );
2339         GtkButton* g_refresh_models_button = toolbar_append_button( toolbar, "Refresh Models", "refresh_models.png", "RefreshReferences" );
2340
2341
2342         // disable the console and texture button in the regular layouts
2343         if ( style == MainFrame::eRegular || style == MainFrame::eRegularLeft ) {
2344                 gtk_widget_set_sensitive( GTK_WIDGET( g_view_console_button ), FALSE );
2345                 gtk_widget_set_sensitive( GTK_WIDGET( g_view_textures_button ), FALSE );
2346         }
2347
2348         return toolbar;
2349 }
2350
2351 GtkWidget* create_main_statusbar( GtkWidget *pStatusLabel[c_count_status] ){
2352         GtkTable* table = GTK_TABLE( gtk_table_new( 1, c_count_status, FALSE ) );
2353         gtk_widget_show( GTK_WIDGET( table ) );
2354
2355         {
2356                 GtkLabel* label = GTK_LABEL( gtk_label_new( "Label" ) );
2357                 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
2358                 gtk_misc_set_padding( GTK_MISC( label ), 4, 2 );
2359                 gtk_widget_show( GTK_WIDGET( label ) );
2360                 gtk_table_attach_defaults( table, GTK_WIDGET( label ), 0, 1, 0, 1 );
2361                 pStatusLabel[c_command_status] = GTK_WIDGET( label );
2362         }
2363
2364         for ( int i = 1; i < c_count_status; ++i )
2365         {
2366                 GtkFrame* frame = GTK_FRAME( gtk_frame_new( 0 ) );
2367                 gtk_widget_show( GTK_WIDGET( frame ) );
2368                 gtk_table_attach_defaults( table, GTK_WIDGET( frame ), i, i + 1, 0, 1 );
2369                 gtk_frame_set_shadow_type( frame, GTK_SHADOW_IN );
2370
2371                 GtkLabel* label = GTK_LABEL( gtk_label_new( "Label" ) );
2372                 gtk_label_set_ellipsize( label, PANGO_ELLIPSIZE_END );
2373                 gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 );
2374                 gtk_misc_set_padding( GTK_MISC( label ), 4, 2 );
2375                 gtk_widget_show( GTK_WIDGET( label ) );
2376                 gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( label ) );
2377                 pStatusLabel[i] = GTK_WIDGET( label );
2378         }
2379
2380         return GTK_WIDGET( table );
2381 }
2382
2383 class MainWindowActive
2384 {
2385 static gboolean notify( GtkWindow* window, gpointer dummy, MainWindowActive* self ){
2386         if ( g_wait.m_window != 0 && gtk_window_is_active( window ) && !GTK_WIDGET_VISIBLE( g_wait.m_window ) ) {
2387                 gtk_widget_show( GTK_WIDGET( g_wait.m_window ) );
2388         }
2389
2390         return FALSE;
2391 }
2392 public:
2393 void connect( GtkWindow* toplevel_window ){
2394         g_signal_connect( G_OBJECT( toplevel_window ), "notify::is-active", G_CALLBACK( notify ), this );
2395 }
2396 };
2397
2398 MainWindowActive g_MainWindowActive;
2399
2400 SignalHandlerId XYWindowDestroyed_connect( const SignalHandler& handler ){
2401         return g_pParentWnd->GetXYWnd()->onDestroyed.connectFirst( handler );
2402 }
2403
2404 void XYWindowDestroyed_disconnect( SignalHandlerId id ){
2405         g_pParentWnd->GetXYWnd()->onDestroyed.disconnect( id );
2406 }
2407
2408 MouseEventHandlerId XYWindowMouseDown_connect( const MouseEventHandler& handler ){
2409         return g_pParentWnd->GetXYWnd()->onMouseDown.connectFirst( handler );
2410 }
2411
2412 void XYWindowMouseDown_disconnect( MouseEventHandlerId id ){
2413         g_pParentWnd->GetXYWnd()->onMouseDown.disconnect( id );
2414 }
2415
2416 // =============================================================================
2417 // MainFrame class
2418
2419 MainFrame* g_pParentWnd = 0;
2420
2421 GtkWindow* MainFrame_getWindow(){
2422         if ( g_pParentWnd == 0 ) {
2423                 return 0;
2424         }
2425         return g_pParentWnd->m_window;
2426 }
2427
2428 std::vector<GtkWidget*> g_floating_windows;
2429
2430 MainFrame::MainFrame() : m_window( 0 ), m_idleRedrawStatusText( RedrawStatusTextCaller( *this ) ){
2431         m_pXYWnd = 0;
2432         m_pCamWnd = 0;
2433         m_pZWnd = 0;
2434         m_pYZWnd = 0;
2435         m_pXZWnd = 0;
2436         m_pActiveXY = 0;
2437
2438         for ( int n = 0; n < c_count_status; n++ )
2439         {
2440                 m_pStatusLabel[n] = 0;
2441         }
2442
2443         m_bSleeping = false;
2444
2445         Create();
2446 }
2447
2448 MainFrame::~MainFrame(){
2449         SaveWindowInfo();
2450
2451         gtk_widget_hide( GTK_WIDGET( m_window ) );
2452
2453         Shutdown();
2454
2455         for ( std::vector<GtkWidget*>::iterator i = g_floating_windows.begin(); i != g_floating_windows.end(); ++i )
2456         {
2457                 gtk_widget_destroy( *i );
2458         }
2459
2460         gtk_widget_destroy( GTK_WIDGET( m_window ) );
2461 }
2462
2463 void MainFrame::SetActiveXY( XYWnd* p ){
2464         if ( m_pActiveXY ) {
2465                 m_pActiveXY->SetActive( false );
2466         }
2467
2468         m_pActiveXY = p;
2469
2470         if ( m_pActiveXY ) {
2471                 m_pActiveXY->SetActive( true );
2472         }
2473
2474 }
2475
2476
2477 void MainFrame::OnSleep(){
2478 }
2479
2480
2481 GtkWindow* create_splash(){
2482         GtkWindow* window = GTK_WINDOW( gtk_window_new( GTK_WINDOW_TOPLEVEL ) );
2483         gtk_window_set_decorated( window, FALSE );
2484         gtk_window_set_resizable( window, FALSE );
2485         gtk_window_set_modal( window, TRUE );
2486         gtk_window_set_default_size( window, -1, -1 );
2487         gtk_window_set_position( window, GTK_WIN_POS_CENTER );
2488         gtk_container_set_border_width( GTK_CONTAINER( window ), 0 );
2489
2490         GtkImage* image = new_local_image( "splash.png" );
2491         gtk_widget_show( GTK_WIDGET( image ) );
2492         gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( image ) );
2493
2494         gtk_widget_set_size_request( GTK_WIDGET( window ), -1, -1 );
2495         gtk_widget_show( GTK_WIDGET( window ) );
2496
2497         return window;
2498 }
2499
2500 static GtkWindow *splash_screen = 0;
2501
2502 void show_splash(){
2503         splash_screen = create_splash();
2504
2505         process_gui();
2506 }
2507
2508 void hide_splash(){
2509         gtk_widget_destroy( GTK_WIDGET( splash_screen ) );
2510 }
2511
2512 WindowPositionTracker g_posCamWnd;
2513 WindowPositionTracker g_posXYWnd;
2514 WindowPositionTracker g_posXZWnd;
2515 WindowPositionTracker g_posYZWnd;
2516
2517 static gint mainframe_delete( GtkWidget *widget, GdkEvent *event, gpointer data ){
2518         if ( ConfirmModified( "Exit Radiant" ) ) {
2519                 gtk_main_quit();
2520         }
2521
2522         return TRUE;
2523 }
2524
2525 void MainFrame::Create(){
2526         GtkWindow* window = GTK_WINDOW( gtk_window_new( GTK_WINDOW_TOPLEVEL ) );
2527
2528         GlobalWindowObservers_connectTopLevel( window );
2529
2530         gtk_window_set_transient_for( splash_screen, window );
2531
2532 #if !defined( WIN32 )
2533         {
2534                 GdkPixbuf* pixbuf = pixbuf_new_from_file_with_mask( "bitmaps/icon.png" );
2535                 if ( pixbuf != 0 ) {
2536                         gtk_window_set_icon( window, pixbuf );
2537                         gdk_pixbuf_unref( pixbuf );
2538                 }
2539         }
2540 #endif
2541
2542         gtk_widget_add_events( GTK_WIDGET( window ), GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK );
2543         g_signal_connect( G_OBJECT( window ), "delete_event", G_CALLBACK( mainframe_delete ), this );
2544
2545         m_position_tracker.connect( window );
2546
2547         g_MainWindowActive.connect( window );
2548
2549         GetPlugInMgr().Init( GTK_WIDGET( window ) );
2550
2551         GtkWidget* vbox = gtk_vbox_new( FALSE, 0 );
2552         gtk_container_add( GTK_CONTAINER( window ), vbox );
2553         gtk_widget_show( vbox );
2554
2555         global_accel_connect_window( window );
2556
2557         m_nCurrentStyle = (EViewStyle)g_Layout_viewStyle.m_value;
2558
2559         register_shortcuts();
2560
2561         GtkMenuBar* main_menu = create_main_menu( CurrentStyle() );
2562         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( main_menu ), FALSE, FALSE, 0 );
2563
2564         GtkToolbar* main_toolbar = create_main_toolbar( CurrentStyle() );
2565         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( main_toolbar ), FALSE, FALSE, 0 );
2566
2567         GtkToolbar* plugin_toolbar = create_plugin_toolbar();
2568         if ( !g_Layout_enablePluginToolbar.m_value ) {
2569                 gtk_widget_hide( GTK_WIDGET( plugin_toolbar ) );
2570         }
2571         gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( plugin_toolbar ), FALSE, FALSE, 0 );
2572
2573         GtkWidget* main_statusbar = create_main_statusbar( m_pStatusLabel );
2574         gtk_box_pack_end( GTK_BOX( vbox ), main_statusbar, FALSE, TRUE, 2 );
2575
2576         GroupDialog_constructWindow( window );
2577         g_page_entity = GroupDialog_addPage( "Entities", EntityInspector_constructWindow( GroupDialog_getWindow() ), RawStringExportCaller( "Entities" ) );
2578
2579         if ( FloatingGroupDialog() ) {
2580                 g_page_console = GroupDialog_addPage( "Console", Console_constructWindow( GroupDialog_getWindow() ), RawStringExportCaller( "Console" ) );
2581         }
2582
2583 #ifdef WIN32
2584         if ( g_multimon_globals.m_bStartOnPrimMon ) {
2585                 PositionWindowOnPrimaryScreen( g_layout_globals.m_position );
2586                 window_set_position( window, g_layout_globals.m_position );
2587         }
2588         else
2589 #endif
2590         if ( g_layout_globals.nState & GDK_WINDOW_STATE_MAXIMIZED ) {
2591                 gtk_window_maximize( window );
2592                 WindowPosition default_position( -1, -1, 640, 480 );
2593                 window_set_position( window, default_position );
2594         }
2595         else
2596         {
2597                 window_set_position( window, g_layout_globals.m_position );
2598         }
2599
2600         m_window = window;
2601
2602         gtk_widget_show( GTK_WIDGET( window ) );
2603
2604         if ( CurrentStyle() == eRegular || CurrentStyle() == eRegularLeft ) {
2605                 {
2606                         GtkWidget* vsplit = gtk_vpaned_new();
2607                         m_vSplit = vsplit;
2608                         gtk_box_pack_start( GTK_BOX( vbox ), vsplit, TRUE, TRUE, 0 );
2609                         gtk_widget_show( vsplit );
2610
2611                         // console
2612                         GtkWidget* console_window = Console_constructWindow( window );
2613                         gtk_paned_pack2( GTK_PANED( vsplit ), console_window, FALSE, TRUE );
2614
2615                         {
2616                                 GtkWidget* hsplit = gtk_hpaned_new();
2617                                 gtk_widget_show( hsplit );
2618                                 m_hSplit = hsplit;
2619                                 gtk_paned_add1( GTK_PANED( vsplit ), hsplit );
2620
2621                                 // xy
2622                                 m_pXYWnd = new XYWnd();
2623                                 m_pXYWnd->SetViewType( XY );
2624                                 GtkWidget* xy_window = GTK_WIDGET( create_framed_widget( m_pXYWnd->GetWidget() ) );
2625
2626                                 {
2627                                         GtkWidget* vsplit2 = gtk_vpaned_new();
2628                                         gtk_widget_show( vsplit2 );
2629                                         m_vSplit2 = vsplit2;
2630
2631                                         if ( CurrentStyle() == eRegular ) {
2632                                                 gtk_paned_add1( GTK_PANED( hsplit ), xy_window );
2633                                                 gtk_paned_add2( GTK_PANED( hsplit ), vsplit2 );
2634                                         }
2635                                         else
2636                                         {
2637                                                 gtk_paned_add1( GTK_PANED( hsplit ), vsplit2 );
2638                                                 gtk_paned_add2( GTK_PANED( hsplit ), xy_window );
2639                                         }
2640
2641
2642                                         // camera
2643                                         m_pCamWnd = NewCamWnd();
2644                                         GlobalCamera_setCamWnd( *m_pCamWnd );
2645                                         CamWnd_setParent( *m_pCamWnd, window );
2646                                         GtkFrame* camera_window = create_framed_widget( CamWnd_getWidget( *m_pCamWnd ) );
2647
2648                                         gtk_paned_add1( GTK_PANED( vsplit2 ), GTK_WIDGET( camera_window ) );
2649
2650                                         // textures
2651                                         GtkFrame* texture_window = create_framed_widget( TextureBrowser_constructWindow( window ) );
2652
2653                                         gtk_paned_add2( GTK_PANED( vsplit2 ), GTK_WIDGET( texture_window ) );
2654                                 }
2655                         }
2656                 }
2657
2658                 gtk_paned_set_position( GTK_PANED( m_vSplit ), g_layout_globals.nXYHeight );
2659
2660                 if ( CurrentStyle() == eRegular ) {
2661                         gtk_paned_set_position( GTK_PANED( m_hSplit ), g_layout_globals.nXYWidth );
2662                 }
2663                 else
2664                 {
2665                         gtk_paned_set_position( GTK_PANED( m_hSplit ), g_layout_globals.nCamWidth );
2666                 }
2667
2668                 gtk_paned_set_position( GTK_PANED( m_vSplit2 ), g_layout_globals.nCamHeight );
2669         }
2670         else if ( CurrentStyle() == eFloating ) {
2671                 {
2672                         GtkWindow* window = create_persistent_floating_window( "Camera", m_window );
2673                         global_accel_connect_window( window );
2674                         g_posCamWnd.connect( window );
2675
2676                         gtk_widget_show( GTK_WIDGET( window ) );
2677
2678                         m_pCamWnd = NewCamWnd();
2679                         GlobalCamera_setCamWnd( *m_pCamWnd );
2680
2681                         {
2682                                 GtkFrame* frame = create_framed_widget( CamWnd_getWidget( *m_pCamWnd ) );
2683                                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( frame ) );
2684                         }
2685                         CamWnd_setParent( *m_pCamWnd, window );
2686
2687                         g_floating_windows.push_back( GTK_WIDGET( window ) );
2688                 }
2689
2690                 {
2691                         GtkWindow* window = create_persistent_floating_window( ViewType_getTitle( XY ), m_window );
2692                         global_accel_connect_window( window );
2693                         g_posXYWnd.connect( window );
2694
2695                         m_pXYWnd = new XYWnd();
2696                         m_pXYWnd->m_parent = window;
2697                         m_pXYWnd->SetViewType( XY );
2698
2699
2700                         {
2701                                 GtkFrame* frame = create_framed_widget( m_pXYWnd->GetWidget() );
2702                                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( frame ) );
2703                         }
2704                         XY_Top_Shown_Construct( window );
2705
2706                         g_floating_windows.push_back( GTK_WIDGET( window ) );
2707                 }
2708
2709                 {
2710                         GtkWindow* window = create_persistent_floating_window( ViewType_getTitle( XZ ), m_window );
2711                         global_accel_connect_window( window );
2712                         g_posXZWnd.connect( window );
2713
2714                         m_pXZWnd = new XYWnd();
2715                         m_pXZWnd->m_parent = window;
2716                         m_pXZWnd->SetViewType( XZ );
2717
2718                         {
2719                                 GtkFrame* frame = create_framed_widget( m_pXZWnd->GetWidget() );
2720                                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( frame ) );
2721                         }
2722
2723                         XZ_Front_Shown_Construct( window );
2724
2725                         g_floating_windows.push_back( GTK_WIDGET( window ) );
2726                 }
2727
2728                 {
2729                         GtkWindow* window = create_persistent_floating_window( ViewType_getTitle( YZ ), m_window );
2730                         global_accel_connect_window( window );
2731                         g_posYZWnd.connect( window );
2732
2733                         m_pYZWnd = new XYWnd();
2734                         m_pYZWnd->m_parent = window;
2735                         m_pYZWnd->SetViewType( YZ );
2736
2737                         {
2738                                 GtkFrame* frame = create_framed_widget( m_pYZWnd->GetWidget() );
2739                                 gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( frame ) );
2740                         }
2741
2742                         YZ_Side_Shown_Construct( window );
2743
2744                         g_floating_windows.push_back( GTK_WIDGET( window ) );
2745                 }
2746
2747                 {
2748                         GtkFrame* frame = create_framed_widget( TextureBrowser_constructWindow( GroupDialog_getWindow() ) );
2749                         g_page_textures = GroupDialog_addPage( "Textures", GTK_WIDGET( frame ), TextureBrowserExportTitleCaller() );
2750                 }
2751
2752                 GroupDialog_show();
2753         }
2754         else // 4 way
2755         {
2756                 m_pCamWnd = NewCamWnd();
2757                 GlobalCamera_setCamWnd( *m_pCamWnd );
2758                 CamWnd_setParent( *m_pCamWnd, window );
2759
2760                 GtkWidget* camera = CamWnd_getWidget( *m_pCamWnd );
2761
2762                 m_pYZWnd = new XYWnd();
2763                 m_pYZWnd->SetViewType( YZ );
2764
2765                 GtkWidget* yz = m_pYZWnd->GetWidget();
2766
2767                 m_pXYWnd = new XYWnd();
2768                 m_pXYWnd->SetViewType( XY );
2769
2770                 GtkWidget* xy = m_pXYWnd->GetWidget();
2771
2772                 m_pXZWnd = new XYWnd();
2773                 m_pXZWnd->SetViewType( XZ );
2774
2775                 GtkWidget* xz = m_pXZWnd->GetWidget();
2776
2777                 GtkHPaned* split = create_split_views( camera, yz, xy, xz );
2778                 gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( split ), TRUE, TRUE, 0 );
2779
2780                 {
2781                         GtkFrame* frame = create_framed_widget( TextureBrowser_constructWindow( window ) );
2782                         g_page_textures = GroupDialog_addPage( "Textures", GTK_WIDGET( frame ), TextureBrowserExportTitleCaller() );
2783                 }
2784         }
2785
2786         EntityList_constructWindow( window );
2787         PreferencesDialog_constructWindow( window );
2788         FindTextureDialog_constructWindow( window );
2789         SurfaceInspector_constructWindow( window );
2790         PatchInspector_constructWindow( window );
2791
2792         SetActiveXY( m_pXYWnd );
2793
2794         AddGridChangeCallback( SetGridStatusCaller( *this ) );
2795         AddGridChangeCallback( ReferenceCaller<MainFrame, XY_UpdateAllWindows>( *this ) );
2796
2797         g_defaultToolMode = DragMode;
2798         g_defaultToolMode();
2799         SetStatusText( m_command_status, c_TranslateMode_status );
2800
2801         EverySecondTimer_enable();
2802
2803 }
2804
2805 void MainFrame::SaveWindowInfo(){
2806         if ( !FloatingGroupDialog() ) {
2807                 g_layout_globals.nXYHeight = gtk_paned_get_position( GTK_PANED( m_vSplit ) );
2808
2809                 if ( CurrentStyle() != eRegular ) {
2810                         g_layout_globals.nCamWidth = gtk_paned_get_position( GTK_PANED( m_hSplit ) );
2811                 }
2812                 else
2813                 {
2814                         g_layout_globals.nXYWidth = gtk_paned_get_position( GTK_PANED( m_hSplit ) );
2815                 }
2816
2817                 g_layout_globals.nCamHeight = gtk_paned_get_position( GTK_PANED( m_vSplit2 ) );
2818         }
2819
2820         g_layout_globals.m_position = m_position_tracker.getPosition();
2821
2822         g_layout_globals.nState = gdk_window_get_state( GTK_WIDGET( m_window )->window );
2823 }
2824
2825 void MainFrame::Shutdown(){
2826         EverySecondTimer_disable();
2827
2828         EntityList_destroyWindow();
2829
2830         delete m_pXYWnd;
2831         m_pXYWnd = 0;
2832         delete m_pYZWnd;
2833         m_pYZWnd = 0;
2834         delete m_pXZWnd;
2835         m_pXZWnd = 0;
2836
2837         TextureBrowser_destroyWindow();
2838
2839         DeleteCamWnd( m_pCamWnd );
2840         m_pCamWnd = 0;
2841
2842         PreferencesDialog_destroyWindow();
2843         SurfaceInspector_destroyWindow();
2844         FindTextureDialog_destroyWindow();
2845         PatchInspector_destroyWindow();
2846
2847         g_DbgDlg.destroyWindow();
2848
2849         // destroying group-dialog last because it may contain texture-browser
2850         GroupDialog_destroyWindow();
2851 }
2852
2853 void MainFrame::RedrawStatusText(){
2854         gtk_label_set_text( GTK_LABEL( m_pStatusLabel[c_command_status] ), m_command_status.c_str() );
2855         gtk_label_set_text( GTK_LABEL( m_pStatusLabel[c_position_status] ), m_position_status.c_str() );
2856         gtk_label_set_text( GTK_LABEL( m_pStatusLabel[c_brushcount_status] ), m_brushcount_status.c_str() );
2857         gtk_label_set_text( GTK_LABEL( m_pStatusLabel[c_texture_status] ), m_texture_status.c_str() );
2858         gtk_label_set_text( GTK_LABEL( m_pStatusLabel[c_grid_status] ), m_grid_status.c_str() );
2859 }
2860
2861 void MainFrame::UpdateStatusText(){
2862         m_idleRedrawStatusText.queueDraw();
2863 }
2864
2865 void MainFrame::SetStatusText( CopiedString& status_text, const char* pText ){
2866         status_text = pText;
2867         UpdateStatusText();
2868 }
2869
2870 void Sys_Status( const char* status ){
2871         if ( g_pParentWnd != 0 ) {
2872                 g_pParentWnd->SetStatusText( g_pParentWnd->m_command_status, status );
2873         }
2874 }
2875
2876 int getRotateIncrement(){
2877         return static_cast<int>( g_si_globals.rotate );
2878 }
2879
2880 int getFarClipDistance(){
2881         return g_camwindow_globals.m_nCubicScale;
2882 }
2883
2884 float ( *GridStatus_getGridSize )() = GetGridSize;
2885 int ( *GridStatus_getRotateIncrement )() = getRotateIncrement;
2886 int ( *GridStatus_getFarClipDistance )() = getFarClipDistance;
2887 bool ( *GridStatus_getTextureLockEnabled )();
2888
2889 void MainFrame::SetGridStatus(){
2890         StringOutputStream status( 64 );
2891         const char* lock = ( GridStatus_getTextureLockEnabled() ) ? "ON" : "OFF";
2892         status << ( GetSnapGridSize() > 0 ? "G:" : "g:" ) << GridStatus_getGridSize()
2893                    << "  R:" << GridStatus_getRotateIncrement()
2894                    << "  C:" << GridStatus_getFarClipDistance()
2895                    << "  L:" << lock;
2896         SetStatusText( m_grid_status, status.c_str() );
2897 }
2898
2899 void GridStatus_onTextureLockEnabledChanged(){
2900         if ( g_pParentWnd != 0 ) {
2901                 g_pParentWnd->SetGridStatus();
2902         }
2903 }
2904
2905 void GlobalGL_sharedContextCreated(){
2906         GLFont *g_font = NULL;
2907
2908         // report OpenGL information
2909         globalOutputStream() << "GL_VENDOR: " << reinterpret_cast<const char*>( glGetString( GL_VENDOR ) ) << "\n";
2910         globalOutputStream() << "GL_RENDERER: " << reinterpret_cast<const char*>( glGetString( GL_RENDERER ) ) << "\n";
2911         globalOutputStream() << "GL_VERSION: " << reinterpret_cast<const char*>( glGetString( GL_VERSION ) ) << "\n";
2912         globalOutputStream() << "GL_EXTENSIONS: " << reinterpret_cast<const char*>( glGetString( GL_EXTENSIONS ) ) << "\n";
2913
2914         QGL_sharedContextCreated( GlobalOpenGL() );
2915
2916         ShaderCache_extensionsInitialised();
2917
2918         GlobalShaderCache().realise();
2919         Textures_Realise();
2920
2921 #ifdef WIN32
2922         /* win32 is dodgy here, just use courier new then */
2923         g_font = glfont_create( "arial 9" );
2924 #else
2925         GtkSettings *settings = gtk_settings_get_default();
2926         gchar *fontname;
2927         g_object_get( settings, "gtk-font-name", &fontname, NULL );
2928         g_font = glfont_create( fontname );
2929 #endif
2930
2931         GlobalOpenGL().m_font = g_font;
2932 }
2933
2934 void GlobalGL_sharedContextDestroyed(){
2935         Textures_Unrealise();
2936         GlobalShaderCache().unrealise();
2937
2938         QGL_sharedContextDestroyed( GlobalOpenGL() );
2939 }
2940
2941
2942 void Layout_constructPreferences( PreferencesPage& page ){
2943         {
2944                 const char* layouts[] = { "window1.png", "window2.png", "window3.png", "window4.png" };
2945                 page.appendRadioIcons(
2946                         "Window Layout",
2947                         STRING_ARRAY_RANGE( layouts ),
2948                         LatchedIntImportCaller( g_Layout_viewStyle ),
2949                         IntExportCaller( g_Layout_viewStyle.m_latched )
2950                         );
2951         }
2952         page.appendCheckBox(
2953                 "", "Detachable Menus",
2954                 LatchedBoolImportCaller( g_Layout_enableDetachableMenus ),
2955                 BoolExportCaller( g_Layout_enableDetachableMenus.m_latched )
2956                 );
2957         if ( !string_empty( g_pGameDescription->getKeyValue( "no_patch" ) ) ) {
2958                 page.appendCheckBox(
2959                         "", "Patch Toolbar",
2960                         LatchedBoolImportCaller( g_Layout_enablePatchToolbar ),
2961                         BoolExportCaller( g_Layout_enablePatchToolbar.m_latched )
2962                         );
2963         }
2964         page.appendCheckBox(
2965                 "", "Plugin Toolbar",
2966                 LatchedBoolImportCaller( g_Layout_enablePluginToolbar ),
2967                 BoolExportCaller( g_Layout_enablePluginToolbar.m_latched )
2968                 );
2969 }
2970
2971 void Layout_constructPage( PreferenceGroup& group ){
2972         PreferencesPage page( group.createPage( "Layout", "Layout Preferences" ) );
2973         Layout_constructPreferences( page );
2974 }
2975
2976 void Layout_registerPreferencesPage(){
2977         PreferencesDialog_addInterfacePage( FreeCaller1<PreferenceGroup&, Layout_constructPage>() );
2978 }
2979
2980
2981 #include "preferencesystem.h"
2982 #include "stringio.h"
2983
2984 void MainFrame_Construct(){
2985         GlobalCommands_insert( "OpenManual", FreeCaller<OpenHelpURL>(), Accelerator( GDK_F1 ) );
2986
2987         GlobalCommands_insert( "Sleep", FreeCaller<thunk_OnSleep>(), Accelerator( 'P', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
2988         GlobalCommands_insert( "NewMap", FreeCaller<NewMap>() );
2989         GlobalCommands_insert( "OpenMap", FreeCaller<OpenMap>(), Accelerator( 'O', (GdkModifierType)GDK_CONTROL_MASK ) );
2990         GlobalCommands_insert( "ImportMap", FreeCaller<ImportMap>() );
2991         GlobalCommands_insert( "SaveMap", FreeCaller<SaveMap>(), Accelerator( 'S', (GdkModifierType)GDK_CONTROL_MASK ) );
2992         GlobalCommands_insert( "SaveMapAs", FreeCaller<SaveMapAs>() );
2993         GlobalCommands_insert( "SaveSelected", FreeCaller<ExportMap>() );
2994         GlobalCommands_insert( "SaveRegion", FreeCaller<SaveRegion>() );
2995         GlobalCommands_insert( "RefreshReferences", FreeCaller<RefreshReferences>() );
2996         GlobalCommands_insert( "ProjectSettings", FreeCaller<DoProjectSettings>() );
2997         GlobalCommands_insert( "CheckForUpdate", FreeCaller<OpenUpdateURL>() );
2998         GlobalCommands_insert( "Exit", FreeCaller<Exit>() );
2999
3000         GlobalCommands_insert( "Undo", FreeCaller<Undo>(), Accelerator( 'Z', (GdkModifierType)GDK_CONTROL_MASK ) );
3001         GlobalCommands_insert( "Redo", FreeCaller<Redo>(), Accelerator( 'Y', (GdkModifierType)GDK_CONTROL_MASK ) );
3002         GlobalCommands_insert( "Copy", FreeCaller<Copy>(), Accelerator( 'C', (GdkModifierType)GDK_CONTROL_MASK ) );
3003         GlobalCommands_insert( "Paste", FreeCaller<Paste>(), Accelerator( 'V', (GdkModifierType)GDK_CONTROL_MASK ) );
3004         GlobalCommands_insert( "PasteToCamera", FreeCaller<PasteToCamera>(), Accelerator( 'V', (GdkModifierType)GDK_MOD1_MASK ) );
3005         GlobalCommands_insert( "CloneSelection", FreeCaller<Selection_Clone>(), Accelerator( GDK_space ) );
3006         GlobalCommands_insert( "CloneSelectionAndMakeUnique", FreeCaller<Selection_Clone_MakeUnique>(), Accelerator( GDK_space, (GdkModifierType)GDK_SHIFT_MASK ) );
3007         GlobalCommands_insert( "DeleteSelection", FreeCaller<deleteSelection>(), Accelerator( GDK_BackSpace ) );
3008         GlobalCommands_insert( "ParentSelection", FreeCaller<Scene_parentSelected>() );
3009         GlobalCommands_insert( "UnSelectSelection", FreeCaller<Selection_Deselect>(), Accelerator( GDK_Escape ) );
3010         GlobalCommands_insert( "InvertSelection", FreeCaller<Select_Invert>(), Accelerator( 'I' ) );
3011         GlobalCommands_insert( "SelectInside", FreeCaller<Select_Inside>() );
3012         GlobalCommands_insert( "SelectTouching", FreeCaller<Select_Touching>() );
3013         GlobalCommands_insert( "ExpandSelectionToEntities", FreeCaller<Scene_ExpandSelectionToEntities>(), Accelerator( 'E', (GdkModifierType)( GDK_MOD1_MASK | GDK_CONTROL_MASK ) ) );
3014         GlobalCommands_insert( "Preferences", FreeCaller<PreferencesDialog_showDialog>(), Accelerator( 'P' ) );
3015
3016         GlobalCommands_insert( "ToggleConsole", FreeCaller<Console_ToggleShow>(), Accelerator( 'O' ) );
3017         GlobalCommands_insert( "ToggleEntityInspector", FreeCaller<EntityInspector_ToggleShow>(), Accelerator( 'N' ) );
3018         GlobalCommands_insert( "EntityList", FreeCaller<EntityList_toggleShown>(), Accelerator( 'L' ) );
3019
3020         GlobalCommands_insert( "ShowHidden", FreeCaller<Select_ShowAllHidden>(), Accelerator( 'H', (GdkModifierType)GDK_SHIFT_MASK ) );
3021         GlobalCommands_insert( "HideSelected", FreeCaller<HideSelected>(), Accelerator( 'H' ) );
3022
3023         GlobalToggles_insert( "DragVertices", FreeCaller<SelectVertexMode>(), ToggleItem::AddCallbackCaller( g_vertexMode_button ), Accelerator( 'V' ) );
3024         GlobalToggles_insert( "DragEdges", FreeCaller<SelectEdgeMode>(), ToggleItem::AddCallbackCaller( g_edgeMode_button ), Accelerator( 'E' ) );
3025         GlobalToggles_insert( "DragFaces", FreeCaller<SelectFaceMode>(), ToggleItem::AddCallbackCaller( g_faceMode_button ), Accelerator( 'F' ) );
3026
3027         GlobalCommands_insert( "MirrorSelectionX", FreeCaller<Selection_Flipx>() );
3028         GlobalCommands_insert( "RotateSelectionX", FreeCaller<Selection_Rotatex>() );
3029         GlobalCommands_insert( "MirrorSelectionY", FreeCaller<Selection_Flipy>() );
3030         GlobalCommands_insert( "RotateSelectionY", FreeCaller<Selection_Rotatey>() );
3031         GlobalCommands_insert( "MirrorSelectionZ", FreeCaller<Selection_Flipz>() );
3032         GlobalCommands_insert( "RotateSelectionZ", FreeCaller<Selection_Rotatez>() );
3033
3034         GlobalCommands_insert( "ArbitraryRotation", FreeCaller<DoRotateDlg>() );
3035         GlobalCommands_insert( "ArbitraryScale", FreeCaller<DoScaleDlg>() );
3036
3037         GlobalCommands_insert( "BuildMenuCustomize", FreeCaller<DoBuildMenu>() );
3038
3039         GlobalCommands_insert( "FindBrush", FreeCaller<DoFind>() );
3040
3041         GlobalCommands_insert( "MapInfo", FreeCaller<DoMapInfo>(), Accelerator( 'M' ) );
3042
3043
3044         GlobalToggles_insert( "ToggleClipper", FreeCaller<ClipperMode>(), ToggleItem::AddCallbackCaller( g_clipper_button ), Accelerator( 'X' ) );
3045
3046         GlobalToggles_insert( "MouseTranslate", FreeCaller<TranslateMode>(), ToggleItem::AddCallbackCaller( g_translatemode_button ), Accelerator( 'W' ) );
3047         GlobalToggles_insert( "MouseRotate", FreeCaller<RotateMode>(), ToggleItem::AddCallbackCaller( g_rotatemode_button ), Accelerator( 'R' ) );
3048         GlobalToggles_insert( "MouseScale", FreeCaller<ScaleMode>(), ToggleItem::AddCallbackCaller( g_scalemode_button ) );
3049         GlobalToggles_insert( "MouseDrag", FreeCaller<DragMode>(), ToggleItem::AddCallbackCaller( g_dragmode_button ), Accelerator( 'Q' ) );
3050
3051         GlobalCommands_insert( "ColorSchemeOriginal", FreeCaller<ColorScheme_Original>() );
3052         GlobalCommands_insert( "ColorSchemeQER", FreeCaller<ColorScheme_QER>() );
3053         GlobalCommands_insert( "ColorSchemeBlackAndGreen", FreeCaller<ColorScheme_Black>() );
3054         GlobalCommands_insert( "ColorSchemeYdnar", FreeCaller<ColorScheme_Ydnar>() );
3055         GlobalCommands_insert( "ChooseTextureBackgroundColor", makeCallback( g_ColoursMenu.m_textureback ) );
3056         GlobalCommands_insert( "ChooseGridBackgroundColor", makeCallback( g_ColoursMenu.m_xyback ) );
3057         GlobalCommands_insert( "ChooseGridMajorColor", makeCallback( g_ColoursMenu.m_gridmajor ) );
3058         GlobalCommands_insert( "ChooseGridMinorColor", makeCallback( g_ColoursMenu.m_gridminor ) );
3059         GlobalCommands_insert( "ChooseSmallGridMajorColor", makeCallback( g_ColoursMenu.m_gridmajor_alt ) );
3060         GlobalCommands_insert( "ChooseSmallGridMinorColor", makeCallback( g_ColoursMenu.m_gridminor_alt ) );
3061         GlobalCommands_insert( "ChooseGridTextColor", makeCallback( g_ColoursMenu.m_gridtext ) );
3062         GlobalCommands_insert( "ChooseGridBlockColor", makeCallback( g_ColoursMenu.m_gridblock ) );
3063         GlobalCommands_insert( "ChooseBrushColor", makeCallback( g_ColoursMenu.m_brush ) );
3064         GlobalCommands_insert( "ChooseCameraBackgroundColor", makeCallback( g_ColoursMenu.m_cameraback ) );
3065         GlobalCommands_insert( "ChooseSelectedBrushColor", makeCallback( g_ColoursMenu.m_selectedbrush ) );
3066         GlobalCommands_insert( "ChooseCameraSelectedBrushColor", makeCallback( g_ColoursMenu.m_selectedbrush3d ) );
3067         GlobalCommands_insert( "ChooseClipperColor", makeCallback( g_ColoursMenu.m_clipper ) );
3068         GlobalCommands_insert( "ChooseOrthoViewNameColor", makeCallback( g_ColoursMenu.m_viewname ) );
3069
3070
3071         GlobalCommands_insert( "CSGSubtract", FreeCaller<CSG_Subtract>(), Accelerator( 'U', (GdkModifierType)GDK_SHIFT_MASK ) );
3072         GlobalCommands_insert( "CSGMerge", FreeCaller<CSG_Merge>(), Accelerator( 'U', (GdkModifierType)GDK_CONTROL_MASK ) );
3073         GlobalCommands_insert( "CSGHollow", FreeCaller<CSG_MakeHollow>() );
3074
3075         Grid_registerCommands();
3076
3077         GlobalCommands_insert( "SnapToGrid", FreeCaller<Selection_SnapToGrid>(), Accelerator( 'G', (GdkModifierType)GDK_CONTROL_MASK ) );
3078
3079         GlobalCommands_insert( "SelectAllOfType", FreeCaller<Select_AllOfType>(), Accelerator( 'A', (GdkModifierType)GDK_SHIFT_MASK ) );
3080
3081         GlobalCommands_insert( "TexRotateClock", FreeCaller<Texdef_RotateClockwise>(), Accelerator( GDK_Next, (GdkModifierType)GDK_SHIFT_MASK ) );
3082         GlobalCommands_insert( "TexRotateCounter", FreeCaller<Texdef_RotateAntiClockwise>(), Accelerator( GDK_Prior, (GdkModifierType)GDK_SHIFT_MASK ) );
3083         GlobalCommands_insert( "TexScaleUp", FreeCaller<Texdef_ScaleUp>(), Accelerator( GDK_Up, (GdkModifierType)GDK_CONTROL_MASK ) );
3084         GlobalCommands_insert( "TexScaleDown", FreeCaller<Texdef_ScaleDown>(), Accelerator( GDK_Down, (GdkModifierType)GDK_CONTROL_MASK ) );
3085         GlobalCommands_insert( "TexScaleLeft", FreeCaller<Texdef_ScaleLeft>(), Accelerator( GDK_Left, (GdkModifierType)GDK_CONTROL_MASK ) );
3086         GlobalCommands_insert( "TexScaleRight", FreeCaller<Texdef_ScaleRight>(), Accelerator( GDK_Right, (GdkModifierType)GDK_CONTROL_MASK ) );
3087         GlobalCommands_insert( "TexShiftUp", FreeCaller<Texdef_ShiftUp>(), Accelerator( GDK_Up, (GdkModifierType)GDK_SHIFT_MASK ) );
3088         GlobalCommands_insert( "TexShiftDown", FreeCaller<Texdef_ShiftDown>(), Accelerator( GDK_Down, (GdkModifierType)GDK_SHIFT_MASK ) );
3089         GlobalCommands_insert( "TexShiftLeft", FreeCaller<Texdef_ShiftLeft>(), Accelerator( GDK_Left, (GdkModifierType)GDK_SHIFT_MASK ) );
3090         GlobalCommands_insert( "TexShiftRight", FreeCaller<Texdef_ShiftRight>(), Accelerator( GDK_Right, (GdkModifierType)GDK_SHIFT_MASK ) );
3091
3092         GlobalCommands_insert( "MoveSelectionDOWN", FreeCaller<Selection_MoveDown>(), Accelerator( GDK_KP_Subtract ) );
3093         GlobalCommands_insert( "MoveSelectionUP", FreeCaller<Selection_MoveUp>(), Accelerator( GDK_KP_Add ) );
3094
3095         GlobalCommands_insert( "SelectNudgeLeft", FreeCaller<Selection_NudgeLeft>(), Accelerator( GDK_Left, (GdkModifierType)GDK_MOD1_MASK ) );
3096         GlobalCommands_insert( "SelectNudgeRight", FreeCaller<Selection_NudgeRight>(), Accelerator( GDK_Right, (GdkModifierType)GDK_MOD1_MASK ) );
3097         GlobalCommands_insert( "SelectNudgeUp", FreeCaller<Selection_NudgeUp>(), Accelerator( GDK_Up, (GdkModifierType)GDK_MOD1_MASK ) );
3098         GlobalCommands_insert( "SelectNudgeDown", FreeCaller<Selection_NudgeDown>(), Accelerator( GDK_Down, (GdkModifierType)GDK_MOD1_MASK ) );
3099
3100         Patch_registerCommands();
3101         XYShow_registerCommands();
3102
3103         typedef FreeCaller1<const Selectable&, ComponentMode_SelectionChanged> ComponentModeSelectionChangedCaller;
3104         GlobalSelectionSystem().addSelectionChangeCallback( ComponentModeSelectionChangedCaller() );
3105
3106         GlobalPreferenceSystem().registerPreference( "DetachableMenus", BoolImportStringCaller( g_Layout_enableDetachableMenus.m_latched ), BoolExportStringCaller( g_Layout_enableDetachableMenus.m_latched ) );
3107         GlobalPreferenceSystem().registerPreference( "PatchToolBar", BoolImportStringCaller( g_Layout_enablePatchToolbar.m_latched ), BoolExportStringCaller( g_Layout_enablePatchToolbar.m_latched ) );
3108         GlobalPreferenceSystem().registerPreference( "PluginToolBar", BoolImportStringCaller( g_Layout_enablePluginToolbar.m_latched ), BoolExportStringCaller( g_Layout_enablePluginToolbar.m_latched ) );
3109         GlobalPreferenceSystem().registerPreference( "QE4StyleWindows", IntImportStringCaller( g_Layout_viewStyle.m_latched ), IntExportStringCaller( g_Layout_viewStyle.m_latched ) );
3110         GlobalPreferenceSystem().registerPreference( "XYHeight", IntImportStringCaller( g_layout_globals.nXYHeight ), IntExportStringCaller( g_layout_globals.nXYHeight ) );
3111         GlobalPreferenceSystem().registerPreference( "XYWidth", IntImportStringCaller( g_layout_globals.nXYWidth ), IntExportStringCaller( g_layout_globals.nXYWidth ) );
3112         GlobalPreferenceSystem().registerPreference( "CamWidth", IntImportStringCaller( g_layout_globals.nCamWidth ), IntExportStringCaller( g_layout_globals.nCamWidth ) );
3113         GlobalPreferenceSystem().registerPreference( "CamHeight", IntImportStringCaller( g_layout_globals.nCamHeight ), IntExportStringCaller( g_layout_globals.nCamHeight ) );
3114
3115         GlobalPreferenceSystem().registerPreference( "State", IntImportStringCaller( g_layout_globals.nState ), IntExportStringCaller( g_layout_globals.nState ) );
3116         GlobalPreferenceSystem().registerPreference( "PositionX", IntImportStringCaller( g_layout_globals.m_position.x ), IntExportStringCaller( g_layout_globals.m_position.x ) );
3117         GlobalPreferenceSystem().registerPreference( "PositionY", IntImportStringCaller( g_layout_globals.m_position.y ), IntExportStringCaller( g_layout_globals.m_position.y ) );
3118         GlobalPreferenceSystem().registerPreference( "Width", IntImportStringCaller( g_layout_globals.m_position.w ), IntExportStringCaller( g_layout_globals.m_position.w ) );
3119         GlobalPreferenceSystem().registerPreference( "Height", IntImportStringCaller( g_layout_globals.m_position.h ), IntExportStringCaller( g_layout_globals.m_position.h ) );
3120
3121         GlobalPreferenceSystem().registerPreference( "CamWnd", WindowPositionTrackerImportStringCaller( g_posCamWnd ), WindowPositionTrackerExportStringCaller( g_posCamWnd ) );
3122         GlobalPreferenceSystem().registerPreference( "XYWnd", WindowPositionTrackerImportStringCaller( g_posXYWnd ), WindowPositionTrackerExportStringCaller( g_posXYWnd ) );
3123         GlobalPreferenceSystem().registerPreference( "YZWnd", WindowPositionTrackerImportStringCaller( g_posYZWnd ), WindowPositionTrackerExportStringCaller( g_posYZWnd ) );
3124         GlobalPreferenceSystem().registerPreference( "XZWnd", WindowPositionTrackerImportStringCaller( g_posXZWnd ), WindowPositionTrackerExportStringCaller( g_posXZWnd ) );
3125
3126         {
3127                 const char* ENGINEPATH_ATTRIBUTE =
3128 #if defined( WIN32 )
3129                         "enginepath_win32"
3130 #elif defined( __APPLE__ )
3131                         "enginepath_macos"
3132 #elif defined( __linux__ ) || defined ( __FreeBSD__ )
3133                         "enginepath_linux"
3134 #else
3135 #error "unknown platform"
3136 #endif
3137                 ;
3138                 StringOutputStream path( 256 );
3139                 path << DirectoryCleaned( g_pGameDescription->getRequiredKeyValue( ENGINEPATH_ATTRIBUTE ) );
3140                 g_strEnginePath = path.c_str();
3141         }
3142
3143         GlobalPreferenceSystem().registerPreference( "EnginePath", CopiedStringImportStringCaller( g_strEnginePath ), CopiedStringExportStringCaller( g_strEnginePath ) );
3144
3145         g_Layout_viewStyle.useLatched();
3146         g_Layout_enableDetachableMenus.useLatched();
3147         g_Layout_enablePatchToolbar.useLatched();
3148         g_Layout_enablePluginToolbar.useLatched();
3149
3150         Layout_registerPreferencesPage();
3151         Paths_registerPreferencesPage();
3152
3153         g_brushCount.setCountChangedCallback( FreeCaller<QE_brushCountChanged>() );
3154         g_entityCount.setCountChangedCallback( FreeCaller<QE_entityCountChanged>() );
3155         GlobalEntityCreator().setCounter( &g_entityCount );
3156
3157         GLWidget_sharedContextCreated = GlobalGL_sharedContextCreated;
3158         GLWidget_sharedContextDestroyed = GlobalGL_sharedContextDestroyed;
3159
3160         GlobalEntityClassManager().attach( g_WorldspawnColourEntityClassObserver );
3161 }
3162
3163 void MainFrame_Destroy(){
3164         GlobalEntityClassManager().detach( g_WorldspawnColourEntityClassObserver );
3165
3166         GlobalEntityCreator().setCounter( 0 );
3167         g_entityCount.setCountChangedCallback( Callback() );
3168         g_brushCount.setCountChangedCallback( Callback() );
3169 }
3170
3171
3172 void GLWindow_Construct(){
3173         GlobalPreferenceSystem().registerPreference( "MouseButtons", IntImportStringCaller( g_glwindow_globals.m_nMouseType ), IntExportStringCaller( g_glwindow_globals.m_nMouseType ) );
3174 }
3175
3176 void GLWindow_Destroy(){
3177 }