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