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