1 /* Copyright (C) 2017 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "Object.h"
21 
22 #include "Buttons/ToolButton.h"
23 #include "General/Datafile.h"
24 #include "ScenarioEditor/ScenarioEditor.h"
25 #include "ScenarioEditor/Tools/Common/ObjectSettings.h"
26 #include "ScenarioEditor/Tools/Common/MiscState.h"
27 #include "VariationControl.h"
28 
29 #include "GameInterface/Messages.h"
30 
31 #include "wx/busyinfo.h"
32 
33 enum
34 {
35 	ID_ObjectType = 1,
36 	ID_ObjectFilter,
37 	ID_PlayerSelect,
38 	ID_SelectObject,
39 	ID_ToggleViewer,
40 	ID_ViewerWireframe,
41 	ID_ViewerMove,
42 	ID_ViewerGround,
43 	ID_ViewerWater,
44 	ID_ViewerShadows,
45 	ID_ViewerPolyCount,
46 	ID_ViewerAnimation,
47 	ID_ViewerBoundingBox,
48 	ID_ViewerAxesMarker,
49 	ID_ViewerPropPoints,
50 	ID_ViewerPlay,
51 	ID_ViewerPause,
52 	ID_ViewerSlow
53 };
54 
55 // Helper function for adding tooltips
Tooltipped(wxWindow * window,const wxString & tip)56 static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
57 {
58 	window->SetToolTip(tip);
59 	return window;
60 }
61 
62 class ObjectBottomBar : public wxPanel
63 {
64 public:
65 	ObjectBottomBar(
66 		wxWindow* parent,
67 		Observable<ObjectSettings>& objectSettings,
68 		Observable<AtObj>& mapSettings,
69 		ObjectSidebarImpl* p
70 	);
71 
72 	void OnFirstDisplay();
73 	void ShowActorViewer(bool show);
74 	void OnSelectedObjectsChange(const std::vector<AtlasMessage::ObjectID>& selectedObjects);
75 
76 private:
77 	void OnViewerSetting(wxCommandEvent& evt);
78 	void OnSelectAnim(wxCommandEvent& evt);
79 	void OnSpeed(wxCommandEvent& evt);
80 
81 	bool m_ViewerWireframe;
82 	bool m_ViewerMove;
83 	bool m_ViewerGround;
84 	bool m_ViewerWater;
85 	bool m_ViewerShadows;
86 	bool m_ViewerPolyCount;
87 	bool m_ViewerBoundingBox;
88 	bool m_ViewerAxesMarker;
89 	int m_ViewerPropPointsMode; // 0 disabled, 1 for point markers, 2 for point markers + axes
90 
91 	wxPanel* m_ViewerPanel;
92 	wxScrolledWindow* m_TemplateNames;
93 
94 	ObjectSidebarImpl* p;
95 	DECLARE_EVENT_TABLE();
96 };
97 
98 struct ObjectSidebarImpl
99 {
ObjectSidebarImplObjectSidebarImpl100 	ObjectSidebarImpl(ScenarioEditor& scenarioEditor) :
101 		m_ObjectListBox(NULL), m_ActorViewerActive(false),
102 		m_ActorViewerEntity(_T("actor|structures/fndn_1x1.xml")),
103 		m_ActorViewerAnimation(_T("idle")), m_ActorViewerSpeed(0.f),
104 		m_ObjectSettings(scenarioEditor.GetObjectSettings())
105 	{
106 	}
107 
108 	wxListBox* m_ObjectListBox;
109 	std::vector<AtlasMessage::sObjectsListItem> m_Objects;
110 	ObservableScopedConnection m_ToolConn;
111 
112 	bool m_ActorViewerActive;
113 	wxString m_ActorViewerEntity;
114 	wxString m_ActorViewerAnimation;
115 	float m_ActorViewerSpeed;
116 	Observable<ObjectSettings>& m_ObjectSettings;
117 
ActorViewerPostToGameObjectSidebarImpl118 	void ActorViewerPostToGame()
119 	{
120 		POST_MESSAGE(SetActorViewer, ((std::wstring)m_ActorViewerEntity.wc_str(), (std::wstring)m_ActorViewerAnimation.wc_str(), m_ObjectSettings.GetPlayerID(), m_ActorViewerSpeed, false));
121 	}
122 };
123 
ObjectSidebar(ScenarioEditor & scenarioEditor,wxWindow * sidebarContainer,wxWindow * bottomBarContainer)124 ObjectSidebar::ObjectSidebar(
125 	ScenarioEditor& scenarioEditor,
126 	wxWindow* sidebarContainer,
127 	wxWindow* bottomBarContainer
128 )
129 	: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer),
130 	  p(new ObjectSidebarImpl(scenarioEditor))
131 {
132 	wxSizer* scrollSizer = new wxBoxSizer(wxVERTICAL);
133 	wxScrolledWindow* scrolledWindow = new wxScrolledWindow(this);
134 	scrolledWindow->SetScrollRate(10, 10);
135 	scrolledWindow->SetSizer(scrollSizer);
136 	m_MainSizer->Add(scrolledWindow, wxSizerFlags().Proportion(1).Expand());
137 
138 	wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
139 	sizer->Add(new wxStaticText(scrolledWindow, wxID_ANY, _("Filter")), wxSizerFlags().Align(wxALIGN_CENTER));
140 	sizer->Add(
141 		Tooltipped(
142 			new wxTextCtrl(scrolledWindow, ID_ObjectFilter),
143 			_("Enter text to filter object list")
144 		),
145 		wxSizerFlags().Expand().Proportion(1)
146 	);
147 	scrollSizer->Add(sizer, wxSizerFlags().Expand());
148 	scrollSizer->AddSpacer(3);
149 
150 	// ------------------------------------------------------------------------------------------
151 
152 	wxArrayString strings;
153 	strings.Add(_("Entities"));
154 	strings.Add(_("Actors (all)"));
155 	wxChoice* objectType = new wxChoice(scrolledWindow, ID_ObjectType, wxDefaultPosition, wxDefaultSize, strings);
156 	objectType->SetSelection(0);
157 	scrollSizer->Add(objectType, wxSizerFlags().Expand());
158 	scrollSizer->AddSpacer(3);
159 
160 	// ------------------------------------------------------------------------------------------
161 
162 	p->m_ObjectListBox = new wxListBox(scrolledWindow, ID_SelectObject, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_HSCROLL);
163 	scrollSizer->Add(p->m_ObjectListBox, wxSizerFlags().Proportion(1).Expand());
164 	scrollSizer->AddSpacer(3);
165 
166 	// ------------------------------------------------------------------------------------------
167 
168 	scrollSizer->Add(new wxButton(scrolledWindow, ID_ToggleViewer, _("Switch to Actor Viewer")), wxSizerFlags().Expand());
169 
170 	// ------------------------------------------------------------------------------------------
171 
172 	m_BottomBar = new ObjectBottomBar(
173 		bottomBarContainer,
174 		scenarioEditor.GetObjectSettings(),
175 		scenarioEditor.GetMapSettings(),
176 		p
177 	);
178 
179 	p->m_ToolConn = scenarioEditor.GetToolManager().GetCurrentTool().RegisterObserver(0, &ObjectSidebar::OnToolChange, this);
180 }
181 
~ObjectSidebar()182 ObjectSidebar::~ObjectSidebar()
183 {
184 	delete p;
185 }
186 
OnToolChange(ITool * tool)187 void ObjectSidebar::OnToolChange(ITool* tool)
188 {
189 	if (wxString(tool->GetClassInfo()->GetClassName()) == _T("ActorViewerTool"))
190 	{
191 		p->m_ActorViewerActive = true;
192 		p->ActorViewerPostToGame();
193 		wxDynamicCast(FindWindow(ID_ToggleViewer), wxButton)->SetLabel(_("Return to game view"));
194 	}
195 	else
196 	{
197 		p->m_ActorViewerActive = false;
198 		wxDynamicCast(FindWindow(ID_ToggleViewer), wxButton)->SetLabel(_("Switch to Actor Viewer"));
199 	}
200 
201 	static_cast<ObjectBottomBar*>(m_BottomBar)->ShowActorViewer(p->m_ActorViewerActive);
202 }
203 
OnFirstDisplay()204 void ObjectSidebar::OnFirstDisplay()
205 {
206 	static_cast<ObjectBottomBar*>(m_BottomBar)->OnFirstDisplay();
207 
208 	wxBusyInfo busy (_("Loading list of objects"));
209 
210 	// Get the list of objects from the game
211 	AtlasMessage::qGetObjectsList qry;
212 	qry.Post();
213 	p->m_Objects = *qry.objects;
214 	// Display first group of objects
215 	FilterObjects();
216 }
217 
FilterObjects()218 void ObjectSidebar::FilterObjects()
219 {
220 	int filterType = wxDynamicCast(FindWindow(ID_ObjectType), wxChoice)->GetSelection();
221 	wxString filterName = wxDynamicCast(FindWindow(ID_ObjectFilter), wxTextCtrl)->GetValue();
222 
223 	p->m_ObjectListBox->Freeze();
224 	p->m_ObjectListBox->Clear();
225 	for (std::vector<AtlasMessage::sObjectsListItem>::iterator it = p->m_Objects.begin(); it != p->m_Objects.end(); ++it)
226 	{
227 		if (it->type == filterType)
228 		{
229 			wxString id = it->id.c_str();
230 			wxString name = it->name.c_str();
231 
232 			if (name.Lower().Find(filterName.Lower()) != wxNOT_FOUND)
233 			{
234 				p->m_ObjectListBox->Append(name, new wxStringClientData(id));
235 			}
236 		}
237 	}
238 	p->m_ObjectListBox->Thaw();
239 }
240 
OnToggleViewer(wxCommandEvent & WXUNUSED (evt))241 void ObjectSidebar::OnToggleViewer(wxCommandEvent& WXUNUSED(evt))
242 {
243 	if (p->m_ActorViewerActive)
244 	{
245 		m_ScenarioEditor.GetToolManager().SetCurrentTool(_T(""), NULL);
246 	}
247 	else
248 	{
249 		m_ScenarioEditor.GetToolManager().SetCurrentTool(_T("ActorViewerTool"), NULL);
250 	}
251 }
252 
OnSelectType(wxCommandEvent & WXUNUSED (evt))253 void ObjectSidebar::OnSelectType(wxCommandEvent& WXUNUSED(evt))
254 {
255 	FilterObjects();
256 }
257 
OnSelectObject(wxCommandEvent & evt)258 void ObjectSidebar::OnSelectObject(wxCommandEvent& evt)
259 {
260 	if (evt.GetInt() < 0)
261 		return;
262 
263 	wxString id = static_cast<wxStringClientData*>(evt.GetClientObject())->GetData();
264 
265 	// Always update the actor viewer's state even if it's inactive,
266 	// so it will be correct when first enabled
267 	p->m_ActorViewerEntity = id;
268 
269 	if (p->m_ActorViewerActive)
270 	{
271 		p->ActorViewerPostToGame();
272 	}
273 	else
274 	{
275 		// On selecting an object, enable the PlaceObject tool with this object
276 		m_ScenarioEditor.GetToolManager().SetCurrentTool(_T("PlaceObject"), &id);
277 	}
278 }
279 
OnSelectFilter(wxCommandEvent & WXUNUSED (evt))280 void ObjectSidebar::OnSelectFilter(wxCommandEvent& WXUNUSED(evt))
281 {
282 	FilterObjects();
283 }
284 
285 BEGIN_EVENT_TABLE(ObjectSidebar, Sidebar)
286 	EVT_CHOICE(ID_ObjectType, ObjectSidebar::OnSelectType)
287 	EVT_TEXT(ID_ObjectFilter, ObjectSidebar::OnSelectFilter)
288 	EVT_LISTBOX(ID_SelectObject, ObjectSidebar::OnSelectObject)
289 	EVT_BUTTON(ID_ToggleViewer, ObjectSidebar::OnToggleViewer)
290 END_EVENT_TABLE();
291 
292 //////////////////////////////////////////////////////////////////////////
293 
294 class PlayerComboBox : public wxComboBox
295 {
296 public:
PlayerComboBox(wxWindow * parent,Observable<ObjectSettings> & objectSettings,Observable<AtObj> & mapSettings)297 	PlayerComboBox(wxWindow* parent, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings)
298 		: wxComboBox(parent, ID_PlayerSelect, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY)
299 		, m_ObjectSettings(objectSettings), m_MapSettings(mapSettings)
300 	{
301 		m_ObjectConn = m_ObjectSettings.RegisterObserver(1, &PlayerComboBox::OnObjectSettingsChange, this);
302 		m_MapConn = m_MapSettings.RegisterObserver(1, &PlayerComboBox::OnMapSettingsChange, this);
303 	}
304 
SetPlayers(wxArrayString & names)305 	void SetPlayers(wxArrayString& names)
306 	{
307 		m_Players = names;
308 		OnMapSettingsChange(m_MapSettings);
309 	}
310 
311 private:
312 
313 	ObservableScopedConnection m_ObjectConn;
314 	Observable<ObjectSettings>& m_ObjectSettings;
315 	ObservableScopedConnection m_MapConn;
316 	Observable<AtObj>& m_MapSettings;
317 	wxArrayString m_Players;
318 
SetSelection(int playerID)319 	void SetSelection(int playerID)
320 	{
321 		// This control may not be loaded yet (before first display)
322 		//	or may have less items than we expect, which could cause
323 		//	an assertion failure, so handle that here
324 		if ((unsigned int)playerID < GetCount())
325 		{
326 			wxComboBox::SetSelection(playerID);
327 		}
328 		else
329 		{
330 			// Invalid selection
331 			wxComboBox::SetSelection(wxNOT_FOUND);
332 		}
333 	}
334 
OnObjectSettingsChange(const ObjectSettings & settings)335 	void OnObjectSettingsChange(const ObjectSettings& settings)
336 	{
337 		SetSelection(settings.GetPlayerID());
338 	}
339 
OnMapSettingsChange(const AtObj & settings)340 	void OnMapSettingsChange(const AtObj& settings)
341 	{
342 		// Reload displayed player names
343 		Clear();
344 		size_t numPlayers = settings["PlayerData"]["item"].count();
345 		for (size_t i = 0; i <= numPlayers && i < m_Players.Count(); ++i)
346 		{
347 			Append(m_Players[i]);
348 		}
349 
350 		SetSelection(m_ObjectSettings.GetPlayerID());
351 	}
352 
OnSelect(wxCommandEvent & evt)353 	void OnSelect(wxCommandEvent& evt)
354 	{
355 		m_ObjectSettings.SetPlayerID(evt.GetInt());
356 		m_ObjectSettings.NotifyObserversExcept(m_ObjectConn);
357 	}
358 
359 	DECLARE_EVENT_TABLE();
360 };
361 BEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox)
362 	EVT_COMBOBOX(wxID_ANY, PlayerComboBox::OnSelect)
363 END_EVENT_TABLE();
364 
365 //////////////////////////////////////////////////////////////////////////
366 
ObjectBottomBar(wxWindow * parent,Observable<ObjectSettings> & objectSettings,Observable<AtObj> & mapSettings,ObjectSidebarImpl * p)367 ObjectBottomBar::ObjectBottomBar(
368 	wxWindow* parent,
369 	Observable<ObjectSettings>& objectSettings,
370 	Observable<AtObj>& mapSettings,
371 	ObjectSidebarImpl* p
372 )
373 	: wxPanel(parent, wxID_ANY), p(p)
374 {
375 	m_ViewerWireframe = false;
376 	m_ViewerMove = false;
377 	m_ViewerGround = true;
378 	m_ViewerWater = false;
379 	m_ViewerShadows = true;
380 	m_ViewerPolyCount = false;
381 	m_ViewerBoundingBox = false;
382 	m_ViewerAxesMarker = false;
383 	m_ViewerPropPointsMode = 0;
384 
385 	wxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL);
386 
387 	// --- viewer options panel -------------------------------------------------------------------------------
388 
389 	m_ViewerPanel = new wxPanel(this, wxID_ANY);
390 	wxSizer* viewerSizer = new wxBoxSizer(wxHORIZONTAL);
391 
392 	wxSizer* viewerButtonsSizer = new wxStaticBoxSizer(wxHORIZONTAL, m_ViewerPanel, _("Display settings"));
393 	{
394 		wxSizer* viewerButtonsLeft = new wxBoxSizer(wxVERTICAL);
395 		viewerButtonsLeft->SetMinSize(110, -1);
396 		viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerWireframe,   _("Wireframe")),      _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand());
397 		viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerMove,        _("Move")),           _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand());
398 		viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerGround,      _("Ground")),         _("Toggle the ground plane")), wxSizerFlags().Expand());
399 		// TODO: disabled until http://trac.wildfiregames.com/ticket/2692 is fixed
400 		wxButton* waterButton = new wxButton(m_ViewerPanel, ID_ViewerWater, _("Water"));
401 		waterButton->Enable(false);
402 		viewerButtonsLeft->Add(Tooltipped(waterButton, _("Toggle the water plane")), wxSizerFlags().Expand());
403 		viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerShadows,     _("Shadows")),        _("Toggle shadow rendering")), wxSizerFlags().Expand());
404 		viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerPolyCount,   _("Poly count")),     _("Toggle polygon-count statistics - turn off ground and shadows for more useful data")), wxSizerFlags().Expand());
405 
406 		wxSizer* viewerButtonsRight = new wxBoxSizer(wxVERTICAL);
407 		viewerButtonsRight->SetMinSize(110,-1);
408 		viewerButtonsRight->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerBoundingBox, _("Bounding Boxes")), _("Toggle bounding boxes")), wxSizerFlags().Expand());
409 		viewerButtonsRight->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerAxesMarker,  _("Axes Marker")), _("Toggle the axes marker (R=X, G=Y, B=Z)")), wxSizerFlags().Expand());
410 		viewerButtonsRight->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerPropPoints,  _("Prop Points")), _("Toggle prop points (works best in wireframe mode)")), wxSizerFlags().Expand());
411 
412 		viewerButtonsSizer->Add(viewerButtonsLeft, wxSizerFlags().Expand());
413 		viewerButtonsSizer->Add(viewerButtonsRight, wxSizerFlags().Expand());
414 	}
415 
416 	viewerSizer->Add(viewerButtonsSizer, wxSizerFlags().Expand());
417 	viewerSizer->AddSpacer(3);
418 
419 	// --- animations panel -------------------------------------------------------------------------------
420 
421 	wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation"));
422 
423 	// TODO: this list should come from the actor
424 	wxArrayString animChoices;
425 	AtObj anims (Datafile::ReadList("animations"));
426 	for (AtIter a = anims["item"]; a.defined(); ++a)
427 	{
428 		animChoices.Add(wxString(*a));
429 	}
430 	wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, animChoices);
431 	viewerAnimSelector->SetSelection(0);
432 	viewerAnimSizer->Add(viewerAnimSelector, wxSizerFlags().Expand());
433 
434 	wxSizer* viewerAnimSpeedSizer = new wxBoxSizer(wxHORIZONTAL);
435 	viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerPlay, _("Play"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand());
436 	viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerPause, _("Pause"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand());
437 	viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerSlow, _("Slow"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand());
438 	viewerAnimSizer->Add(viewerAnimSpeedSizer);
439 
440 	viewerSizer->Add(viewerAnimSizer, wxSizerFlags().Expand());
441 
442 	// --- add viewer-specific options -------------------------------------------------------------------------------
443 
444 	m_ViewerPanel->SetSizer(viewerSizer);
445 	mainSizer->Add(m_ViewerPanel, wxSizerFlags().Expand());
446 
447 	m_ViewerPanel->Layout(); // prevents strange visibility glitch of the animation buttons on my machine (Vista 32-bit SP1) -- vtsj
448 	m_ViewerPanel->Show(false);
449 
450 	// --- add player/variation selection -------------------------------------------------------------------------------
451 
452 	wxSizer* playerSelectionSizer = new wxBoxSizer(wxHORIZONTAL);
453 	wxSizer* playerVariationSizer = new wxBoxSizer(wxVERTICAL);
454 
455 	// TODO: make this a wxChoice instead
456 	wxComboBox* playerSelect = new PlayerComboBox(this, objectSettings, mapSettings);
457 	playerSelectionSizer->Add(new wxStaticText(this, wxID_ANY, _("Player:")), wxSizerFlags().Align(wxALIGN_CENTER));
458 	playerSelectionSizer->AddSpacer(3);
459 	playerSelectionSizer->Add(playerSelect);
460 
461 	playerVariationSizer->Add(playerSelectionSizer);
462 	playerVariationSizer->AddSpacer(3);
463 
464 
465 	wxWindow* variationSelect = new VariationControl(this, objectSettings);
466 	variationSelect->SetMinSize(wxSize(160, -1));
467 	wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Variation"));
468 	variationSizer->Add(variationSelect, wxSizerFlags().Proportion(1).Expand());
469 	playerVariationSizer->Add(variationSizer, wxSizerFlags().Proportion(1));
470 
471 	mainSizer->AddSpacer(3);
472 	mainSizer->Add(playerVariationSizer, wxSizerFlags().Expand());
473 
474 	// ----------------------------------------------------------------------------------
475 	// --- display template name
476 	wxSizer* displaySizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Selected entities"));
477 	m_TemplateNames = new wxScrolledWindow(this);
478 	m_TemplateNames->SetMinSize(wxSize(250, -1));
479 	m_TemplateNames->SetScrollRate(0, 5);
480 	wxSizer* scrollwindowSizer = new wxBoxSizer(wxVERTICAL);
481 	m_TemplateNames->SetSizer(scrollwindowSizer);
482 	displaySizer->Add(m_TemplateNames, wxSizerFlags().Proportion(1).Expand());
483 	m_TemplateNames->Layout();
484 	mainSizer->AddSpacer(3);
485 	mainSizer->Add(displaySizer, wxSizerFlags().Proportion(1).Expand());
486 
487 	g_SelectedObjects.RegisterObserver(0, &ObjectBottomBar::OnSelectedObjectsChange, this);
488 
489 	SetSizer(mainSizer);
490 }
491 
CreateTemplateNameObject(wxWindow * parent,const std::string & templateName,int counterTemplate)492 static wxControl* CreateTemplateNameObject(wxWindow* parent, const std::string& templateName, int counterTemplate)
493 {
494 	wxString idTemplate(wxString::FromUTF8(templateName.c_str()));
495 	if (counterTemplate > 1)
496 		idTemplate.Append(wxString::Format(wxT(" (%i)"), counterTemplate));
497 
498 	wxStaticText* templateNameObject = new wxStaticText(parent, wxID_ANY, idTemplate);
499 	return templateNameObject;
500 }
501 
OnSelectedObjectsChange(const std::vector<AtlasMessage::ObjectID> & selectedObjects)502 void ObjectBottomBar::OnSelectedObjectsChange(const std::vector<AtlasMessage::ObjectID>& selectedObjects)
503 {
504 	Freeze();
505 	wxSizer* sizer = m_TemplateNames->GetSizer();
506 	sizer->Clear(true);
507 
508 	AtlasMessage::qGetSelectedObjectsTemplateNames objectTemplatesName(selectedObjects);
509 	objectTemplatesName.Post();
510 	std::vector<std::string> names = *objectTemplatesName.names;
511 
512 	int counterTemplate = 0;
513 	std::string lastTemplateName = "";
514 	for (std::vector<std::string>::const_iterator it = names.begin(); it != names.end(); ++it)
515 	{
516 		if (lastTemplateName == "")
517 			lastTemplateName = (*it);
518 
519 		if (lastTemplateName == (*it))
520 		{
521 			++counterTemplate;
522 			continue;
523 		}
524 
525 		sizer->Add(CreateTemplateNameObject(m_TemplateNames, lastTemplateName, counterTemplate), wxSizerFlags().Align(wxALIGN_LEFT));
526 
527 		lastTemplateName = (*it);
528 		counterTemplate = 1;
529 	}
530 	// Add the remaining template
531 	sizer->Add(CreateTemplateNameObject(m_TemplateNames, lastTemplateName, counterTemplate), wxSizerFlags().Align(wxALIGN_LEFT));
532 
533 	Thaw();
534 	sizer->FitInside(m_TemplateNames);
535 }
536 
OnFirstDisplay()537 void ObjectBottomBar::OnFirstDisplay()
538 {
539 	// We use messages here because the simulation is not init'd otherwise (causing a crash)
540 
541 	// Get player names
542 	wxArrayString players;
543 	AtlasMessage::qGetPlayerDefaults qryPlayers;
544 	qryPlayers.Post();
545 	AtObj playerData = AtlasObject::LoadFromJSON(*qryPlayers.defaults);
546 	AtObj playerDefs = *playerData["PlayerData"];
547 	for (AtIter p = playerDefs["item"]; p.defined(); ++p)
548 	{
549 		players.Add(wxString(p["Name"]));
550 	}
551 	wxDynamicCast(FindWindow(ID_PlayerSelect), PlayerComboBox)->SetPlayers(players);
552 
553 	// Initialise the game with the default settings
554 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"wireframe", m_ViewerWireframe));
555 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove));
556 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"ground", m_ViewerGround));
557 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"water", m_ViewerWater));
558 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", m_ViewerShadows));
559 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"stats", m_ViewerPolyCount));
560 	POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"bounding_box", m_ViewerBoundingBox));
561 	POST_MESSAGE(SetViewParamI, (AtlasMessage::eRenderView::ACTOR, L"prop_points", m_ViewerPropPointsMode));
562 }
563 
ShowActorViewer(bool show)564 void ObjectBottomBar::ShowActorViewer(bool show)
565 {
566 	m_ViewerPanel->Show(show);
567 	Layout();
568 }
569 
OnViewerSetting(wxCommandEvent & evt)570 void ObjectBottomBar::OnViewerSetting(wxCommandEvent& evt)
571 {
572 	switch (evt.GetId())
573 	{
574 	case ID_ViewerWireframe:
575 		m_ViewerWireframe = !m_ViewerWireframe;
576 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"wireframe", m_ViewerWireframe));
577 		break;
578 	case ID_ViewerMove:
579 		m_ViewerMove = !m_ViewerMove;
580 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove));
581 		break;
582 	case ID_ViewerGround:
583 		m_ViewerGround = !m_ViewerGround;
584 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"ground", m_ViewerGround));
585 		break;
586 	case ID_ViewerWater:
587 		m_ViewerWater = !m_ViewerWater;
588 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"water", m_ViewerWater));
589 		break;
590 	case ID_ViewerShadows:
591 		m_ViewerShadows = !m_ViewerShadows;
592 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", m_ViewerShadows));
593 		break;
594 	case ID_ViewerPolyCount:
595 		m_ViewerPolyCount = !m_ViewerPolyCount;
596 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"stats", m_ViewerPolyCount));
597 		break;
598 	case ID_ViewerBoundingBox:
599 		m_ViewerBoundingBox = !m_ViewerBoundingBox;
600 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"bounding_box", m_ViewerBoundingBox));
601 		break;
602 	case ID_ViewerAxesMarker:
603 		m_ViewerAxesMarker = !m_ViewerAxesMarker;
604 		POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"axes_marker", m_ViewerAxesMarker));
605 		break;
606 	case ID_ViewerPropPoints:
607 		m_ViewerPropPointsMode = (m_ViewerPropPointsMode+1) % 3;
608 		POST_MESSAGE(SetViewParamI, (AtlasMessage::eRenderView::ACTOR, L"prop_points", m_ViewerPropPointsMode));
609 		break;
610 	}
611 }
612 
OnSelectAnim(wxCommandEvent & evt)613 void ObjectBottomBar::OnSelectAnim(wxCommandEvent& evt)
614 {
615 	p->m_ActorViewerAnimation = evt.GetString();
616 	p->ActorViewerPostToGame();
617 }
618 
OnSpeed(wxCommandEvent & evt)619 void ObjectBottomBar::OnSpeed(wxCommandEvent& evt)
620 {
621 	switch (evt.GetId())
622 	{
623 	case ID_ViewerPlay: p->m_ActorViewerSpeed = 1.0f; break;
624 	case ID_ViewerPause: p->m_ActorViewerSpeed = 0.0f; break;
625 	case ID_ViewerSlow: p->m_ActorViewerSpeed = 0.1f; break;
626 	}
627 	p->ActorViewerPostToGame();
628 }
629 
630 BEGIN_EVENT_TABLE(ObjectBottomBar, wxPanel)
631 	EVT_BUTTON(ID_ViewerWireframe, ObjectBottomBar::OnViewerSetting)
632 	EVT_BUTTON(ID_ViewerMove, ObjectBottomBar::OnViewerSetting)
633 	EVT_BUTTON(ID_ViewerGround, ObjectBottomBar::OnViewerSetting)
634 	EVT_BUTTON(ID_ViewerWater, ObjectBottomBar::OnViewerSetting)
635 	EVT_BUTTON(ID_ViewerShadows, ObjectBottomBar::OnViewerSetting)
636 	EVT_BUTTON(ID_ViewerPolyCount, ObjectBottomBar::OnViewerSetting)
637 	EVT_CHOICE(ID_ViewerAnimation, ObjectBottomBar::OnSelectAnim)
638 	EVT_BUTTON(ID_ViewerPlay, ObjectBottomBar::OnSpeed)
639 	EVT_BUTTON(ID_ViewerPause, ObjectBottomBar::OnSpeed)
640 	EVT_BUTTON(ID_ViewerSlow, ObjectBottomBar::OnSpeed)
641 	EVT_BUTTON(ID_ViewerBoundingBox, ObjectBottomBar::OnViewerSetting)
642 	EVT_BUTTON(ID_ViewerAxesMarker, ObjectBottomBar::OnViewerSetting)
643 	EVT_BUTTON(ID_ViewerPropPoints, ObjectBottomBar::OnViewerSetting)
644 END_EVENT_TABLE();
645