1 #include "GlobalXYWnd.h"
2
3 #include "ieventmanager.h"
4
5 #include "gtkutil/FramedTransientWidget.h"
6 #include "stringio.h"
7 #include "../select.h"
8 #include "../selection/algorithm/General.h"
9 #include "../ui/mainframe/mainframe.h"
10 #include "radiant_i18n.h"
11
12 // Constructor
XYWndManager()13 XYWndManager::XYWndManager() :
14 _activeXY(NULL), _globalParentWindow(NULL)
15 {
16 // Connect self to the according registry keys
17 GlobalRegistry().addKeyObserver(this, RKEY_CHASE_MOUSE);
18 GlobalRegistry().addKeyObserver(this, RKEY_CAMERA_XY_UPDATE);
19 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_CROSSHAIRS);
20 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_GRID);
21 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_SIZE_INFO);
22 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_ENTITY_ANGLES);
23 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_ENTITY_NAMES);
24 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_BLOCKS);
25 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_COORDINATES);
26 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_OUTLINE);
27 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_AXES);
28 GlobalRegistry().addKeyObserver(this, RKEY_SHOW_WORKZONE);
29 GlobalRegistry().addKeyObserver(this, RKEY_DEFAULT_BLOCKSIZE);
30 GlobalRegistry().addKeyObserver(this, RKEY_ALWAYS_CAULK_FOR_NEW_BRUSHES);
31 GlobalRegistry().addKeyObserver(this, RKEY_CAULK_TEXTURE);
32
33 // Trigger loading the values of the observed registry keys
34 keyChanged("", "");
35
36 // greebo: Register this class in the preference system so that the constructPreferencePage() gets called.
37 GlobalPreferenceSystem().addConstructor(this);
38
39 // Add the commands to the EventManager
40 registerCommands();
41 }
42
43 // Destructor
~XYWndManager()44 XYWndManager::~XYWndManager() {
45 }
46
construct()47 void XYWndManager::construct() {
48 XYWnd::captureStates();
49 }
50
51 // Free the allocated XYViews from the heap
destroyViews()52 void XYWndManager::destroyViews() {
53 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
54 // Free the view from the heap
55 XYWnd* xyView = *i;
56
57 delete xyView;
58 }
59 // Discard the whole list
60 _XYViews.clear();
61 }
62
63 // Release the shader states
destroy()64 void XYWndManager::destroy() {
65 XYWnd::releaseStates();
66 }
67
registerCommands()68 void XYWndManager::registerCommands() {
69 GlobalEventManager().addCommand("NewOrthoView", MemberCaller<XYWndManager, &XYWndManager::createNewOrthoView> (
70 *this));
71
72 GlobalEventManager().addCommand("NextView", MemberCaller<XYWndManager, &XYWndManager::toggleActiveView>(*this));
73 GlobalEventManager().addCommand("ZoomIn", MemberCaller<XYWndManager, &XYWndManager::zoomIn>(*this));
74 GlobalEventManager().addCommand("ZoomOut", MemberCaller<XYWndManager, &XYWndManager::zoomOut>(*this));
75 GlobalEventManager().addCommand("ViewTop", MemberCaller<XYWndManager, &XYWndManager::setActiveViewXY>(*this));
76 GlobalEventManager().addCommand("ViewSide", MemberCaller<XYWndManager, &XYWndManager::setActiveViewXZ>(*this));
77 GlobalEventManager().addCommand("ViewFront", MemberCaller<XYWndManager, &XYWndManager::setActiveViewYZ>(*this));
78 GlobalEventManager().addCommand("CenterXYViews", MemberCaller<XYWndManager, &XYWndManager::splitViewFocus>(*this));
79 GlobalEventManager().addCommand("CenterXYView", MemberCaller<XYWndManager, &XYWndManager::focusActiveView>(*this));
80 GlobalEventManager().addCommand("Zoom100", MemberCaller<XYWndManager, &XYWndManager::zoom100>(*this));
81
82 GlobalEventManager().addRegistryToggle("ToggleCrosshairs", RKEY_SHOW_CROSSHAIRS);
83 GlobalEventManager().addRegistryToggle("ToggleGrid", RKEY_SHOW_GRID);
84 GlobalEventManager().addRegistryToggle("ShowAngles", RKEY_SHOW_ENTITY_ANGLES);
85 GlobalEventManager().addRegistryToggle("ShowNames", RKEY_SHOW_ENTITY_NAMES);
86 GlobalEventManager().addRegistryToggle("ShowBlocks", RKEY_SHOW_BLOCKS);
87 GlobalEventManager().addRegistryToggle("ShowCoordinates", RKEY_SHOW_COORDINATES);
88 GlobalEventManager().addRegistryToggle("ShowWindowOutline", RKEY_SHOW_OUTLINE);
89 GlobalEventManager().addRegistryToggle("ShowAxes", RKEY_SHOW_AXES);
90 GlobalEventManager().addRegistryToggle("ShowWorkzone", RKEY_SHOW_WORKZONE);
91 GlobalEventManager().addRegistryToggle("ToggleAlwaysCaulk", RKEY_ALWAYS_CAULK_FOR_NEW_BRUSHES);
92 }
93
constructPreferencePage(PreferenceGroup & group)94 void XYWndManager::constructPreferencePage(PreferenceGroup& group) {
95 PreferencesPage* page(group.createPage(_("Orthographic"), _("Orthographic View Settings")));
96
97 page->appendCheckBox("", _("View chases mouse cursor during drags"), RKEY_CHASE_MOUSE);
98 page->appendCheckBox("", _("Update views on camera move"), RKEY_CAMERA_XY_UPDATE);
99 page->appendCheckBox("", _("Show Crosshairs"), RKEY_SHOW_CROSSHAIRS);
100 page->appendCheckBox("", _("Show Grid"), RKEY_SHOW_GRID);
101 page->appendCheckBox("", _("Show Size Info"), RKEY_SHOW_SIZE_INFO);
102 page->appendCheckBox("", _("Show Entity Angle Arrow"), RKEY_SHOW_ENTITY_ANGLES);
103 page->appendCheckBox("", _("Show Entity Names"), RKEY_SHOW_ENTITY_NAMES);
104 page->appendCheckBox("", _("Show Blocks"), RKEY_SHOW_BLOCKS);
105 page->appendCheckBox("", _("Show Coordinates"), RKEY_SHOW_COORDINATES);
106 page->appendCheckBox("", _("Show Axes"), RKEY_SHOW_AXES);
107 page->appendCheckBox("", _("Show Window Outline"), RKEY_SHOW_OUTLINE);
108 page->appendCheckBox("", _("Show Workzone"), RKEY_SHOW_WORKZONE);
109 page->appendCheckBox("", _("Always caulk for new brushes"), RKEY_ALWAYS_CAULK_FOR_NEW_BRUSHES);
110 page->appendTextureEntry(_("Caulk texture name"), RKEY_CAULK_TEXTURE);
111 }
112
113 // Load/Reload the values from the registry
keyChanged(const std::string & changedKey,const std::string & newValue)114 void XYWndManager::keyChanged(const std::string& changedKey, const std::string& newValue) {
115 _chaseMouse = (GlobalRegistry().get(RKEY_CHASE_MOUSE) == "1");
116 _camXYUpdate = (GlobalRegistry().get(RKEY_CAMERA_XY_UPDATE) == "1");
117 _showCrossHairs = (GlobalRegistry().get(RKEY_SHOW_CROSSHAIRS) == "1");
118 _showGrid = (GlobalRegistry().get(RKEY_SHOW_GRID) == "1");
119 _showSizeInfo = (GlobalRegistry().get(RKEY_SHOW_SIZE_INFO) == "1");
120 _showBlocks = (GlobalRegistry().get(RKEY_SHOW_BLOCKS) == "1");
121 _showCoordinates = (GlobalRegistry().get(RKEY_SHOW_COORDINATES) == "1");
122 _showOutline = (GlobalRegistry().get(RKEY_SHOW_OUTLINE) == "1");
123 _showAxes = (GlobalRegistry().get(RKEY_SHOW_AXES) == "1");
124 _showWorkzone = (GlobalRegistry().get(RKEY_SHOW_WORKZONE) == "1");
125 _defaultBlockSize = (GlobalRegistry().getInt(RKEY_DEFAULT_BLOCKSIZE));
126 _alwaysCaulkForNewBrushes = (GlobalRegistry().get(RKEY_ALWAYS_CAULK_FOR_NEW_BRUSHES) == "1");
127 _caulkTexture = GlobalRegistry().get(RKEY_CAULK_TEXTURE);
128
129 updateAllViews();
130 }
131
chaseMouse() const132 bool XYWndManager::chaseMouse() const {
133 return _chaseMouse;
134 }
135
camXYUpdate() const136 bool XYWndManager::camXYUpdate() const {
137 return _camXYUpdate;
138 }
139
showCrossHairs() const140 bool XYWndManager::showCrossHairs() const {
141 return _showCrossHairs;
142 }
143
showBlocks() const144 bool XYWndManager::showBlocks() const {
145 return _showBlocks;
146 }
147
defaultBlockSize() const148 unsigned int XYWndManager::defaultBlockSize() const {
149 return _defaultBlockSize;
150 }
151
showCoordinates() const152 bool XYWndManager::showCoordinates() const {
153 return _showCoordinates;
154 }
155
showOutline() const156 bool XYWndManager::showOutline() const {
157 return _showOutline;
158 }
159
showAxes() const160 bool XYWndManager::showAxes() const {
161 return _showAxes;
162 }
163
showWorkzone() const164 bool XYWndManager::showWorkzone() const {
165 return _showWorkzone;
166 }
167
showGrid() const168 bool XYWndManager::showGrid() const {
169 return _showGrid;
170 }
171
showSizeInfo() const172 bool XYWndManager::showSizeInfo() const {
173 return _showSizeInfo;
174 }
175
getCaulkTexture() const176 std::string XYWndManager::getCaulkTexture() const {
177 return _caulkTexture;
178 }
179
alwaysCaulkForNewBrushes() const180 bool XYWndManager::alwaysCaulkForNewBrushes() const {
181 return _alwaysCaulkForNewBrushes;
182 }
183
updateAllViews()184 void XYWndManager::updateAllViews() {
185 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
186 XYWnd* xyview = *i;
187
188 // Pass the call
189 xyview->queueDraw();
190 }
191 }
192
zoomIn()193 void XYWndManager::zoomIn() {
194 if (_activeXY != NULL) {
195 _activeXY->zoomIn();
196 }
197 }
198
zoomOut()199 void XYWndManager::zoomOut() {
200 if (_activeXY != NULL) {
201 _activeXY->zoomOut();
202 }
203 }
204
setActiveViewXY()205 void XYWndManager::setActiveViewXY() {
206 setActiveViewType(XY);
207 positionView(getFocusPosition());
208 }
209
setActiveViewXZ()210 void XYWndManager::setActiveViewXZ() {
211 setActiveViewType(XZ);
212 positionView(getFocusPosition());
213 }
214
setActiveViewYZ()215 void XYWndManager::setActiveViewYZ() {
216 setActiveViewType(YZ);
217 positionView(getFocusPosition());
218 }
219
splitViewFocus()220 void XYWndManager::splitViewFocus() {
221 positionAllViews(getFocusPosition());
222 }
223
zoom100()224 void XYWndManager::zoom100() {
225 GlobalXYWnd().setScale(1);
226 }
227
focusActiveView()228 void XYWndManager::focusActiveView() {
229 positionView(getFocusPosition());
230 }
231
getActiveXY() const232 XYWnd* XYWndManager::getActiveXY() const {
233 return _activeXY;
234 }
235
setOrigin(const Vector3 & origin)236 void XYWndManager::setOrigin(const Vector3& origin) {
237 // Cycle through the list of views and set the origin
238 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
239 XYWnd* xyView = *i;
240
241 if (xyView != NULL) {
242 // Pass the call
243 xyView->setOrigin(origin);
244 }
245 }
246 }
247
setScale(float scale)248 void XYWndManager::setScale(float scale) {
249 // Cycle through the list of views and set the origin
250 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
251 XYWnd* xyView = *i;
252
253 if (xyView != NULL) {
254 // Pass the call
255 xyView->setScale(scale);
256 }
257 }
258 }
259
positionAllViews(const Vector3 & origin)260 void XYWndManager::positionAllViews(const Vector3& origin) {
261 // Cycle through the list of views and set the origin
262 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
263 XYWnd* xyView = *i;
264
265 if (xyView != NULL) {
266 // Pass the call
267 xyView->positionView(origin);
268 }
269 }
270 }
271
positionView(const Vector3 & origin)272 void XYWndManager::positionView(const Vector3& origin) {
273 if (_activeXY != NULL) {
274 return _activeXY->positionView(origin);
275 }
276 }
277
getActiveViewType() const278 EViewType XYWndManager::getActiveViewType() const {
279 if (_activeXY != NULL) {
280 return _activeXY->getViewType();
281 }
282 // Return at least anything
283 return XY;
284 }
285
setActiveViewType(EViewType viewType)286 void XYWndManager::setActiveViewType(EViewType viewType) {
287 if (_activeXY != NULL) {
288 return _activeXY->setViewType(viewType);
289 }
290 }
291
toggleActiveView()292 void XYWndManager::toggleActiveView() {
293 if (_activeXY != NULL) {
294 if (_activeXY->getViewType() == XY) {
295 _activeXY->setViewType(XZ);
296 }
297 else if (_activeXY->getViewType() == XZ) {
298 _activeXY->setViewType(YZ);
299 }
300 else {
301 _activeXY->setViewType(XY);
302 }
303 }
304
305 positionView(getFocusPosition());
306 }
307
getView(EViewType viewType)308 XYWnd* XYWndManager::getView(EViewType viewType) {
309 // Cycle through the list of views and get the one matching the type
310 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
311 XYWnd* xyView = *i;
312
313 if (xyView != NULL) {
314 // If the view matches, return the pointer
315 if (xyView->getViewType() == viewType) {
316 return xyView;
317 }
318 }
319 }
320
321 return NULL;
322 }
323
setActiveXY(XYWnd * wnd)324 void XYWndManager::setActiveXY(XYWnd* wnd) {
325 // Notify the currently active XYView that is has been deactivated
326 if (_activeXY != NULL) {
327 _activeXY->setActive(false);
328 }
329
330 // Update the pointer
331 _activeXY = wnd;
332
333 // Notify the new active XYView about its activation
334 if (_activeXY != NULL) {
335 _activeXY->setActive(true);
336 }
337 }
338
createXY()339 XYWnd* XYWndManager::createXY() {
340 // Allocate a new window
341 XYWnd* newWnd = new XYWnd();
342
343 // Add it to the internal list and return the pointer
344 _XYViews.push_back(newWnd);
345
346 // Tag the new view as active, if there is no active view yet
347 if (_activeXY == NULL) {
348 _activeXY = newWnd;
349 }
350
351 return newWnd;
352 }
353
setGlobalParentWindow(GtkWindow * globalParentWindow)354 void XYWndManager::setGlobalParentWindow(GtkWindow* globalParentWindow) {
355 _globalParentWindow = globalParentWindow;
356 }
357
destroyOrthoView(XYWnd * xyWnd)358 void XYWndManager::destroyOrthoView(XYWnd* xyWnd) {
359 if (xyWnd != NULL) {
360
361 // Remove the pointer from the list
362 for (XYWndList::iterator i = _XYViews.begin(); i != _XYViews.end(); ++i) {
363 XYWnd* listItem = (*i);
364
365 // If the view is found, remove it from the list
366 if (listItem == xyWnd) {
367 // Retrieve the parent from the view (for later destruction)
368 GtkWindow* parent = xyWnd->getParent();
369 GtkWidget* glWidget = xyWnd->getWidget();
370
371 if (_activeXY == xyWnd) {
372 _activeXY = NULL;
373 }
374
375 // Destroy the window
376 delete xyWnd;
377
378 // Remove it from the list
379 _XYViews.erase(i);
380
381 // Destroy the parent window (and the contained frame) as well
382 if (parent != NULL) {
383 gtk_widget_destroy(GTK_WIDGET(glWidget));
384 gtk_widget_destroy(GTK_WIDGET(parent));
385 }
386
387 break;
388 }
389 }
390 }
391 }
392
onDeleteOrthoView(GtkWidget * widget,GdkEvent * event,gpointer data)393 gboolean XYWndManager::onDeleteOrthoView(GtkWidget *widget, GdkEvent *event, gpointer data) {
394 // Get the pointer to the deleted XY view from data
395 XYWnd* deletedView = reinterpret_cast<XYWnd*>(data);
396
397 GlobalXYWnd().destroyOrthoView(deletedView);
398
399 return false;
400 }
401
createOrthoView(EViewType viewType)402 void XYWndManager::createOrthoView(EViewType viewType) {
403
404 // Allocate a new XYWindow
405 XYWnd* newWnd = createXY();
406
407 // Add the new XYView GL widget to a framed window
408 GtkWidget* window = gtkutil::FramedTransientWidget(XYWnd::getViewTypeTitle(viewType), _globalParentWindow,
409 newWnd->getWidget());
410
411 // Connect the destroyed signal to the callback of this class
412 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(onDeleteOrthoView), newWnd);
413
414 newWnd->setParent(GTK_WINDOW(window));
415
416 // Set the viewtype (and with it the window title)
417 newWnd->setViewType(viewType);
418 }
419
420 // Shortcut method for connecting to a GlobalEventManager command
createNewOrthoView()421 void XYWndManager::createNewOrthoView() {
422 createOrthoView(XY);
423 }
424
425 /* greebo: This function determines the point currently being "looked" at, it is used for toggling the ortho views
426 * If something is selected the center of the selection is taken as new origin, otherwise the camera
427 * position is considered to be the new origin of the toggled orthoview.
428 */
getFocusPosition()429 Vector3 XYWndManager::getFocusPosition() {
430 Vector3 position(0,0,0);
431
432 if (GlobalSelectionSystem().countSelected() != 0) {
433 position = selection::algorithm::getCurrentSelectionCenter();
434 }
435 else {
436 position = g_pParentWnd->GetCamWnd()->getCameraOrigin();
437 }
438
439 return position;
440 }
441
442 // Accessor function returning a reference to the static instance
GlobalXYWnd()443 XYWndManager& GlobalXYWnd() {
444 static XYWndManager _xyWndManager;
445 return _xyWndManager;
446 }
447