diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp new file mode 100644 index 0000000000..4c774f5ca7 --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp @@ -0,0 +1,168 @@ +#include "stdafx.h" + +#include "Map.h" + +#include "General/Datafile.h" +#include "ScenarioEditor/Tools/Common/Tools.h" + +#include "GameInterface/Messages.h" + +#include "wx/filename.h" + +enum +{ + ID_GenerateMap, + ID_GenerateRMS, + ID_SimPlay, + ID_SimFast, + ID_SimSlow, + ID_SimPause, + ID_SimReset +}; + +enum +{ + SimInactive, + SimPlaying, + SimPlayingFast, + SimPlayingSlow, + SimPaused +}; +bool IsPlaying(int s) { return (s == SimPlaying || s == SimPlayingFast || s == SimPlayingSlow); } + +MapSidebar::MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer) + : Sidebar(sidebarContainer, bottomBarContainer), m_SimState(SimInactive) +{ + // TODO: Less ugliness + // TODO: Intercept arrow keys and send them to the GL window + + m_MainSizer->Add(new wxButton(this, ID_GenerateMap, _("Generate empty map"))); + + { + wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + m_RMSText = new wxTextCtrl(this, wxID_ANY, _T("cantabrian_highlands")); + sizer->Add(m_RMSText); + sizer->Add(new wxButton(this, ID_GenerateRMS, _("Generate RMS"))); + m_MainSizer->Add(sizer); + } + + { + wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Simulation test")); + sizer->Add(new wxButton(this, ID_SimPlay, _("Play")), wxSizerFlags().Proportion(1)); + sizer->Add(new wxButton(this, ID_SimFast, _("Fast")), wxSizerFlags().Proportion(1)); + sizer->Add(new wxButton(this, ID_SimSlow, _("Slow")), wxSizerFlags().Proportion(1)); + sizer->Add(new wxButton(this, ID_SimPause, _("Pause")), wxSizerFlags().Proportion(1)); + sizer->Add(new wxButton(this, ID_SimReset, _("Reset")), wxSizerFlags().Proportion(1)); + UpdateSimButtons(); + m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 16)); + } +} + +void MapSidebar::GenerateMap(wxCommandEvent& WXUNUSED(event)) +{ + POST_MESSAGE(GenerateMap, (9)); +} + +void MapSidebar::GenerateRMS(wxCommandEvent& WXUNUSED(event)) +{ + wxChar* argv[] = { _T("rmgen.exe"), 0, _T("_atlasrm"), 0 }; + wxString scriptName = m_RMSText->GetValue(); + argv[1] = const_cast(scriptName.c_str()); + + wxString cwd = wxFileName::GetCwd(); + wxFileName::SetCwd(Datafile::GetDataDirectory()); + wxExecute(argv, wxEXEC_SYNC); + wxFileName::SetCwd(cwd); + + POST_MESSAGE(LoadMap, (L"_atlasrm.pmp")); +} + +void MapSidebar::UpdateSimButtons() +{ + wxButton* button; + + button = wxDynamicCast(FindWindow(ID_SimPlay), wxButton); + wxCHECK(button, ); + button->Enable(m_SimState != SimPlaying); + + button = wxDynamicCast(FindWindow(ID_SimFast), wxButton); + wxCHECK(button, ); + button->Enable(m_SimState != SimPlayingFast); + + button = wxDynamicCast(FindWindow(ID_SimSlow), wxButton); + wxCHECK(button, ); + button->Enable(m_SimState != SimPlayingSlow); + + button = wxDynamicCast(FindWindow(ID_SimPause), wxButton); + wxCHECK(button, ); + button->Enable(IsPlaying(m_SimState)); + + button = wxDynamicCast(FindWindow(ID_SimReset), wxButton); + wxCHECK(button, ); + button->Enable(m_SimState != SimInactive); +} + +void MapSidebar::OnSimPlay(wxCommandEvent& event) +{ + float speed = 1.f; + int newState = SimPlaying; + if (event.GetId() == ID_SimFast) + { + speed = 8.f; + newState = SimPlayingFast; + } + else if (event.GetId() == ID_SimSlow) + { + speed = 0.125f; + newState = SimPlayingSlow; + } + + if (m_SimState == SimInactive) + { + POST_MESSAGE(SimStateSave, (L"default", true)); + POST_MESSAGE(SimPlay, (speed)); + m_SimState = newState; + } + else // paused or already playing at a different speed + { + POST_MESSAGE(SimPlay, (speed)); + m_SimState = newState; + } + UpdateSimButtons(); +} + +void MapSidebar::OnSimPause(wxCommandEvent& WXUNUSED(event)) +{ + if (IsPlaying(m_SimState)) + { + POST_MESSAGE(SimPlay, (0.f)); + m_SimState = SimPaused; + } + UpdateSimButtons(); +} + +void MapSidebar::OnSimReset(wxCommandEvent& WXUNUSED(event)) +{ + if (IsPlaying(m_SimState)) + { + POST_MESSAGE(SimPlay, (0.f)); + POST_MESSAGE(SimStateRestore, (L"default")); + m_SimState = SimInactive; + } + else if (m_SimState == SimPaused) + { + POST_MESSAGE(SimStateRestore, (L"default")); + m_SimState = SimInactive; + } + UpdateSimButtons(); +} + +BEGIN_EVENT_TABLE(MapSidebar, Sidebar) + EVT_BUTTON(ID_GenerateMap, MapSidebar::GenerateMap) + EVT_BUTTON(ID_GenerateRMS, MapSidebar::GenerateRMS) + EVT_BUTTON(ID_SimPlay, MapSidebar::OnSimPlay) + EVT_BUTTON(ID_SimFast, MapSidebar::OnSimPlay) + EVT_BUTTON(ID_SimSlow, MapSidebar::OnSimPlay) + EVT_BUTTON(ID_SimPause, MapSidebar::OnSimPause) + EVT_BUTTON(ID_SimReset, MapSidebar::OnSimReset) +END_EVENT_TABLE(); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h new file mode 100644 index 0000000000..ff7fc67911 --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.h @@ -0,0 +1,22 @@ +#include "../Common/Sidebar.h" + +class MapSidebar : public Sidebar +{ +public: + MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer); + +private: + void GenerateMap(wxCommandEvent& event); + void GenerateRMS(wxCommandEvent& event); + + wxTextCtrl* m_RMSText; + + void OnSimPlay(wxCommandEvent& event); + void OnSimPause(wxCommandEvent& event); + void OnSimReset(wxCommandEvent& event); + void UpdateSimButtons(); + + int m_SimState; + + DECLARE_EVENT_TABLE(); +}; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp new file mode 100644 index 0000000000..bb26ef7fa5 --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.cpp @@ -0,0 +1,208 @@ +/* Copyright (C) 2009 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Object.h" + +#include "Buttons/ToolButton.h" +#include "ScenarioEditor/ScenarioEditor.h" +#include "ScenarioEditor/Tools/Common/ObjectSettings.h" +#include "ScenarioEditor/Tools/Common/MiscState.h" +#include "VariationControl.h" + +#include "GameInterface/Messages.h" + +#include "wx/busyinfo.h" + +class ObjectSelectListBox : public wxListBox +{ +public: + ObjectSelectListBox(wxWindow* parent, ToolManager& toolManager) + : wxListBox(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_HSCROLL) + , m_ToolManager(toolManager) + { + } + + void OnSelect(wxCommandEvent& evt) + { + // On selecting an object, enable the PlaceObject tool with this object + wxString id = static_cast(evt.GetClientObject())->GetData(); + m_ToolManager.SetCurrentTool(_T("PlaceObject"), &id); + } + +private: + ToolManager& m_ToolManager; + DECLARE_EVENT_TABLE(); +}; +BEGIN_EVENT_TABLE(ObjectSelectListBox, wxListBox) + EVT_LISTBOX(wxID_ANY, ObjectSelectListBox::OnSelect) +END_EVENT_TABLE(); + + +class ObjectChoiceCtrl : public wxChoice +{ +public: + ObjectChoiceCtrl(wxWindow* parent, const wxArrayString& strings, ObjectSidebar& sidebar) + : wxChoice(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, strings), + m_Sidebar(sidebar) + { + SetSelection(0); + } + + void OnSelect(wxCommandEvent& evt) + { + // Switch between displayed lists of objects (e.g. entities vs actors) + m_Sidebar.SetObjectFilter(evt.GetSelection()); + } + +private: + ObjectSidebar& m_Sidebar; + + DECLARE_EVENT_TABLE(); +}; +BEGIN_EVENT_TABLE(ObjectChoiceCtrl, wxChoice) + EVT_CHOICE(wxID_ANY, ObjectChoiceCtrl::OnSelect) +END_EVENT_TABLE(); + +////////////////////////////////////////////////////////////////////////// + + +class ObjectBottomBar : public wxPanel +{ +public: + ObjectBottomBar(wxWindow* parent, Observable& objectSettings); +}; + +struct ObjectSidebarImpl +{ + ObjectSidebarImpl() : m_BottomBar(NULL), m_ObjectListBox(NULL) { } + wxWindow* m_BottomBar; + wxListBox* m_ObjectListBox; + std::vector m_Objects; +}; + +ObjectSidebar::ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) +: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), p(new ObjectSidebarImpl()) +{ + wxArrayString strings; + strings.Add(_("Entities")); + strings.Add(_("Actors (all)")); + m_MainSizer->Add(new ObjectChoiceCtrl(this, strings, *this), wxSizerFlags().Expand()); + + p->m_ObjectListBox = new ObjectSelectListBox(this, scenarioEditor.GetToolManager()); + m_MainSizer->Add(p->m_ObjectListBox, wxSizerFlags().Proportion(1).Expand()); + + m_BottomBar = new ObjectBottomBar(bottomBarContainer, scenarioEditor.GetObjectSettings()); +} + +ObjectSidebar::~ObjectSidebar() +{ + delete p; +} + +void ObjectSidebar::OnFirstDisplay() +{ + wxBusyInfo busy (_("Loading list of objects")); + + // Get the list of objects from the game + AtlasMessage::qGetObjectsList qry; + qry.Post(); + p->m_Objects = *qry.objects; + // Display first group of objects + SetObjectFilter(0); +} + +void ObjectSidebar::SetObjectFilter(int type) +{ + p->m_ObjectListBox->Freeze(); + p->m_ObjectListBox->Clear(); + for (std::vector::iterator it = p->m_Objects.begin(); it != p->m_Objects.end(); ++it) + { + if (it->type == type) + { + wxString id = it->id.c_str(); + wxString name = it->name.c_str(); + p->m_ObjectListBox->Append(name, new wxStringClientData(id)); + } + } + p->m_ObjectListBox->Thaw(); +} + +////////////////////////////////////////////////////////////////////////// + +class PlayerComboBox : public wxComboBox +{ +public: + PlayerComboBox(wxWindow* parent, wxArrayString& choices, Observable& objectSettings) + : wxComboBox(parent, -1, choices[objectSettings.GetPlayerID()], wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY) + , m_ObjectSettings(objectSettings) + { + m_Conn = m_ObjectSettings.RegisterObserver(1, &PlayerComboBox::OnObjectSettingsChange, this); + } + +private: + + ObservableScopedConnection m_Conn; + Observable& m_ObjectSettings; + + void OnObjectSettingsChange(const ObjectSettings& settings) + { + SetSelection((long)settings.GetPlayerID()); + } + + void OnSelect(wxCommandEvent& evt) + { + m_ObjectSettings.SetPlayerID(evt.GetInt()); + m_ObjectSettings.NotifyObserversExcept(m_Conn); + } + + DECLARE_EVENT_TABLE(); +}; +BEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox) + EVT_COMBOBOX(wxID_ANY, PlayerComboBox::OnSelect) +END_EVENT_TABLE(); + +////////////////////////////////////////////////////////////////////////// + +ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable& objectSettings) + : wxPanel(parent, wxID_ANY) +{ + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + + wxArrayString players; + // TODO: get proper player names + players.Add(_("Gaia")); + players.Add(_("Player 1")); + players.Add(_("Player 2")); + players.Add(_("Player 3")); + players.Add(_("Player 4")); + players.Add(_("Player 5")); + players.Add(_("Player 6")); + players.Add(_("Player 7")); + players.Add(_("Player 8")); + wxComboBox* playerSelect = new PlayerComboBox(this, players, objectSettings); + sizer->Add(playerSelect); + + wxWindow* variationSelect = new VariationControl(this, objectSettings); + variationSelect->SetMinSize(wxSize(160, -1)); + wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Variation")); + variationSizer->Add(variationSelect, wxSizerFlags().Proportion(1).Expand()); + sizer->Add(variationSizer, wxSizerFlags().Proportion(1)); + + SetSizer(sizer); +} diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.h new file mode 100644 index 0000000000..3c02e0870a --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/Object.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2009 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "../Common/Sidebar.h" + +struct ObjectSidebarImpl; +class ObjectSidebar : public Sidebar +{ +public: + ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer); + ~ObjectSidebar(); + void SetObjectFilter(int type); + +protected: + virtual void OnFirstDisplay(); + +private: + ObjectSidebarImpl* p; +}; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/VariationControl.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/VariationControl.cpp new file mode 100644 index 0000000000..66bbb7400b --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/VariationControl.cpp @@ -0,0 +1,146 @@ +/* Copyright (C) 2009 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "VariationControl.h" + +#include "ScenarioEditor/Tools/Common/ObjectSettings.h" + +VariationControl::VariationControl(wxWindow* parent, Observable& objectSettings) +: wxScrolledWindow(parent, -1), +m_ObjectSettings(objectSettings) +{ + m_Conn = m_ObjectSettings.RegisterObserver(1, &VariationControl::OnObjectSettingsChange, this); + + SetScrollRate(0, 5); + + m_Sizer = new wxBoxSizer(wxVERTICAL); + SetSizer(m_Sizer); +} + +// Event handler shared by all the combo boxes created by this window +void VariationControl::OnSelect(wxCommandEvent& evt) +{ + std::set selections; + + // It's possible for a variant name to appear in multiple groups. + // If so, assume that all the names in each group are the same, so + // we don't have to worry about some impossible combinations (e.g. + // one group "a,b", a second "b,c", and a third "c,a", where's there's + // no set of selections that matches one (and only one) of each group). + // + // So... When a combo box is changed from 'a' to 'b', add 'b' to the new + // selections and make sure any other combo boxes containing both 'a' and + // 'b' no longer contain 'a'. + + wxComboBox* thisComboBox = wxDynamicCast(evt.GetEventObject(), wxComboBox); + wxCHECK(thisComboBox != NULL, ); + wxString newValue = thisComboBox->GetValue(); + + selections.insert(newValue); + + for (size_t i = 0; i < m_ComboBoxes.size(); ++i) + { + wxComboBox* comboBox = m_ComboBoxes[i]; + // If our newly selected value is used in another combobox, we want + // that combobox to use the new value, so don't add its old value + // to the list of selections + if (comboBox->FindString(newValue) == wxNOT_FOUND) + selections.insert(comboBox->GetValue()); + } + + m_ObjectSettings.SetActorSelections(selections); + m_ObjectSettings.NotifyObserversExcept(m_Conn); + RefreshObjectSettings(); +} + +void VariationControl::OnObjectSettingsChange(const ObjectSettings& settings) +{ + Freeze(); + + const std::vector& variation = settings.GetActorVariation(); + + // Creating combo boxes seems to be pretty expensive - so we create as + // few as possible, by never deleting any. + + size_t oldCount = m_ComboBoxes.size(); + size_t newCount = variation.size(); + + // If we have too many combo boxes, hide the excess ones + for (size_t i = newCount; i < oldCount; ++i) + { + m_ComboBoxes[i]->Show(false); + } + + for (size_t i = 0; i < variation.size(); ++i) + { + const ObjectSettings::Group& group = variation[i]; + + if (i < oldCount) + { + // Already got enough boxes available, so use an old one + wxComboBox* comboBox = m_ComboBoxes[i]; + // Replace the contents of the old combobox with the new data + comboBox->Freeze(); + comboBox->Clear(); + comboBox->Append(group.variants); + comboBox->SetValue(group.chosen); + comboBox->Show(true); + comboBox->Thaw(); + } + else + { + // Create an initially empty combobox, because we can fill it + // quicker than the default constructor can + wxComboBox* combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition, + wxSize(80, wxDefaultCoord), wxArrayString(), wxCB_READONLY); + // Freeze it before adding all the values + combo->Freeze(); + combo->Append(group.variants); + combo->SetValue(group.chosen); + combo->Thaw(); + // Add the on-select event handler + combo->Connect(wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, + wxCommandEventHandler(VariationControl::OnSelect), NULL, this); + // Add box to sizer and list + m_Sizer->Add(combo, wxSizerFlags().Expand()); + m_ComboBoxes.push_back(combo); + } + } + + Layout(); + + Thaw(); + + // Make the scrollbars appear when appropriate + FitInside(); +} + +void VariationControl::RefreshObjectSettings() +{ + const std::vector& variation = m_ObjectSettings.GetActorVariation(); + + // For each group, set the corresponding combobox's value to the chosen one + size_t i = 0; + for (std::vector::const_iterator group = variation.begin(); + group != variation.end() && i < m_ComboBoxes.size(); + ++group, ++i) + { + m_ComboBoxes[i]->SetValue(group->chosen); + } +} diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/VariationControl.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/VariationControl.h new file mode 100644 index 0000000000..1088f3788f --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Object/VariationControl.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2009 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_VARIATIONCONTROL +#define INCLUDED_VARIATIONCONTROL + +#include "General/Observable.h" + +class ObjectSettings; + +class VariationControl : public wxScrolledWindow +{ +public: + VariationControl(wxWindow* parent, Observable& objectSettings); + +private: + void OnSelect(wxCommandEvent& evt); + void OnObjectSettingsChange(const ObjectSettings& settings); + void RefreshObjectSettings(); + + ObservableScopedConnection m_Conn; + + Observable& m_ObjectSettings; + std::vector m_ComboBoxes; + wxSizer* m_Sizer; +}; + +#endif // INCLUDED_VARIATIONCONTROL diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp new file mode 100644 index 0000000000..4f7b9835f7 --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp @@ -0,0 +1,239 @@ +/* Copyright (C) 2009 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Terrain.h" + +#include "Buttons/ToolButton.h" +#include "General/Datafile.h" +#include "ScenarioEditor/ScenarioEditor.h" +#include "ScenarioEditor/Tools/Common/Brushes.h" +#include "ScenarioEditor/Tools/Common/MiscState.h" + +#include "GameInterface/Messages.h" + +#include "wx/spinctrl.h" +#include "wx/listctrl.h" +#include "wx/image.h" +#include "wx/imaglist.h" +#include "wx/busyinfo.h" +#include "wx/notebook.h" + +class TextureNotebook; + +class TerrainBottomBar : public wxPanel +{ +public: + TerrainBottomBar(wxWindow* parent); + void LoadTerrain(); +private: + TextureNotebook* m_Textures; +}; + + +TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) +: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer) +{ + // TODO: Less ugliness + + m_MainSizer->Add(new wxStaticText(this, wxID_ANY, _T("TODO: Make this much less ugly\n"))); + + { + wxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Elevation tools")); + sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Modify"), _T("AlterElevation"), wxSize(50,20))); + sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T("SmoothElevation"), wxSize(50,20))); + sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Flatten"), _T("FlattenElevation"), wxSize(50,20))); +// sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T(""), wxSize(50,20))); +// sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Sample"), _T(""), wxSize(50,20))); + sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Paint"), _T("PaintTerrain"), wxSize(50,20))); + m_MainSizer->Add(sizer); + } + + { + wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Brush")); + g_Brush_Elevation.CreateUI(this, sizer); + m_MainSizer->Add(sizer); + } + + m_BottomBar = new TerrainBottomBar(bottomBarContainer); +} + +void TerrainSidebar::OnFirstDisplay() +{ + static_cast(m_BottomBar)->LoadTerrain(); +} + +////////////////////////////////////////////////////////////////////////// + +class TextureNotebookPage : public wxPanel +{ +public: + TextureNotebookPage(wxWindow* parent, const wxString& name) + : wxPanel(parent, wxID_ANY), m_Name(name), m_ListCtrl(NULL) + { + } + + void OnDisplay() + { + if (m_ListCtrl) + { + int sel = m_ListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (sel != -1) + SetSelection(m_ListCtrl->GetItemData(sel)); + return; + } + + wxBusyInfo busy (_("Loading terrain previews")); + + m_TextureNames.Clear(); + + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + + m_ListCtrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_ICON | wxLC_SINGLE_SEL | wxLC_AUTOARRANGE); + + const int imageWidth = 64; + const int imageHeight = 32; + wxImageList* imglist = new wxImageList(imageWidth, imageHeight, false, 0); + + AtlasMessage::qGetTerrainGroupPreviews qry(m_Name.c_str(), imageWidth, imageHeight); + qry.Post(); + + std::vector previews = *qry.previews; + + int i = 0; + for (std::vector::iterator it = previews.begin(); it != previews.end(); ++it) + { + unsigned char* buf = (unsigned char*)(malloc(it->imagedata.GetSize())); + // it->imagedata.GetBuffer() gives a Shareable*, which + // is stored the same as a unsigned char*, so we can just copy it. + memcpy(buf, it->imagedata.GetBuffer(), it->imagedata.GetSize()); + wxImage img (imageWidth, imageHeight, buf); + imglist->Add(wxBitmap(img)); + + wxListItem item; + + wxString name = it->name.c_str(); + m_TextureNames.Add(name); + // Add spaces into the displayed name, so Windows doesn't just say + // "grass_..." in the list ctrl for every terrain + name.Replace(_T("_"), _T(" ")); + item.SetText(name); + + item.SetData(i); + item.SetId(i); + item.SetImage(i); + + m_ListCtrl->InsertItem(item); + ++i; + } + m_ListCtrl->AssignImageList(imglist, wxIMAGE_LIST_NORMAL); + + sizer->Add(m_ListCtrl, wxSizerFlags().Expand().Proportion(1)); + SetSizer(sizer); + Layout(); // required to make things size correctly + } + + void OnSelect(wxListEvent& evt) + { + SetSelection(evt.GetData()); + } + + void SetSelection(int n) + { + if (n >= 0 && n < (int)m_TextureNames.GetCount()) + g_SelectedTexture = m_TextureNames[n]; + } + +private: + wxListCtrl* m_ListCtrl; + wxString m_Name; + wxArrayString m_TextureNames; + + DECLARE_EVENT_TABLE(); +}; + +BEGIN_EVENT_TABLE(TextureNotebookPage, wxPanel) + EVT_LIST_ITEM_SELECTED(wxID_ANY, TextureNotebookPage::OnSelect) +END_EVENT_TABLE(); + + +class TextureNotebook : public wxNotebook +{ +public: + TextureNotebook(wxWindow *parent) + : wxNotebook(parent, wxID_ANY/*, wxDefaultPosition, wxDefaultSize, wxNB_FIXEDWIDTH*/) + { + } + + void LoadTerrain() + { + wxBusyInfo busy (_("Loading terrain groups")); + + DeleteAllPages(); + m_TerrainGroups.Clear(); + + // Get the list of terrain groups from the engine + AtlasMessage::qGetTerrainGroups qry; + qry.Post(); + std::vector groupnames = *qry.groupnames; + for (std::vector::iterator it = groupnames.begin(); it != groupnames.end(); ++it) + m_TerrainGroups.Add(it->c_str()); + + for (size_t i = 0; i < m_TerrainGroups.GetCount(); ++i) + { + wxString visibleName = m_TerrainGroups[i]; + if (visibleName.Len()) + visibleName[0] = wxToupper(visibleName[0]); + AddPage(new TextureNotebookPage(this, m_TerrainGroups[i]), visibleName); + } + } + +protected: + void OnPageChanged(wxNotebookEvent& event) + { + if (event.GetSelection() >= 0 && event.GetSelection() < (int)GetPageCount()) + { + static_cast(GetPage(event.GetSelection()))->OnDisplay(); + } + event.Skip(); + } + +private: + wxArrayString m_TerrainGroups; + DECLARE_EVENT_TABLE(); +}; + +BEGIN_EVENT_TABLE(TextureNotebook, wxNotebook) + EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TextureNotebook::OnPageChanged) +END_EVENT_TABLE(); + +////////////////////////////////////////////////////////////////////////// + +TerrainBottomBar::TerrainBottomBar(wxWindow* parent) + : wxPanel(parent, wxID_ANY) +{ + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + m_Textures = new TextureNotebook(this); + sizer->Add(m_Textures, wxSizerFlags().Expand().Proportion(1)); + SetSizer(sizer); +} + +void TerrainBottomBar::LoadTerrain() +{ + m_Textures->LoadTerrain(); +} diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h new file mode 100644 index 0000000000..719b2a2cdf --- /dev/null +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.h @@ -0,0 +1,27 @@ +/* Copyright (C) 2009 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "../Common/Sidebar.h" + +class TerrainSidebar : public Sidebar +{ +public: + TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer); + +protected: + virtual void OnFirstDisplay(); +}; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.cpp index 17a87f1ae0..171267f41a 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.cpp @@ -21,46 +21,133 @@ #include "GameInterface/Messages.h" #include "ScenarioEditor/ScenarioEditor.h" -#include "AtlasScript/ScriptInterface.h" -ObjectSettings::ObjectSettings(Observable >& selectedObjects, ScriptInterface& scriptInterface) -: m_ScriptInterface(scriptInterface) +ObjectSettings::ObjectSettings(Observable >& selectedObjects, int view) +: m_PlayerID(0), m_SelectedObjects(selectedObjects), m_View(view) { - m_Conn = selectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this); + m_Conn = m_SelectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this); } -void ObjectSettings::Init(int view) +size_t ObjectSettings::GetPlayerID() const { - m_ScriptInterface.SetValue(_T("Atlas.State.objectSettings.view"), view); + return m_PlayerID; } void ObjectSettings::SetPlayerID(int playerID) { - m_ScriptInterface.SetValue(_T("Atlas.State.objectSettings.playerID"), playerID); + m_PlayerID = playerID; + PostToGame(); +} + +const std::set& ObjectSettings::GetActorSelections() const +{ + return m_ActorSelections; +} + +void ObjectSettings::SetActorSelections(const std::set& selections) +{ + m_ActorSelections = selections; + PostToGame(); +} + +const std::vector ObjectSettings::GetActorVariation() const +{ + std::vector variation; + + for (std::vector::const_iterator grp = m_VariantGroups.begin(); + grp != m_VariantGroups.end(); + ++grp) + { + Group group; + group.variants = *grp; + + // Variant choice method, as used by the game: Choose the first variant + // which matches any of the selections + + size_t chosen = 0; // default to first + for (size_t i = 0; i < grp->GetCount(); ++i) + { + if (m_ActorSelections.find(grp->Item(i)) != m_ActorSelections.end()) + { + chosen = i; + break; + } + } + group.chosen = grp->Item(chosen); + + variation.push_back(group); + } + + return variation; } AtlasMessage::sObjectSettings ObjectSettings::GetSettings() const { AtlasMessage::sObjectSettings settings; - bool ok = m_ScriptInterface.Eval(_T("Atlas.State.objectSettings.toSObjectSettings()"), settings); - wxCHECK(ok, AtlasMessage::sObjectSettings()); + + settings.player = m_PlayerID; + + // Copy selections from set into vector + std::vector selections; + for (std::set::const_iterator it = m_ActorSelections.begin(); + it != m_ActorSelections.end(); + ++it) + { + selections.push_back(it->c_str()); + } + settings.selections = selections; + return settings; } void ObjectSettings::OnSelectionChange(const std::vector& selection) { - // Convert to int so they can be passed to JS - // (manual loop instead of vector range ctor avoids conversion warning) - std::vector objs; - objs.reserve(selection.size()); - for(std::vector::const_iterator it = selection.begin(); it != selection.end(); ++it) - objs.push_back((int)*it); + // TODO: what would be the sensible action if nothing's selected? + // and if multiple objects are selected? - m_ScriptInterface.SetValue(_T("Atlas.State.objectSettings.selectedObjects"), objs); - m_ScriptInterface.Eval(_T("Atlas.State.objectSettings.onSelectionChange()")); + if (selection.empty()) + return; + + AtlasMessage::qGetObjectSettings qry (m_View, selection[0]); + qry.Post(); + + m_PlayerID = qry.settings->player; + + m_ActorSelections.clear(); + m_VariantGroups.clear(); + + std::vector > variation = *qry.settings->variantgroups; + for (std::vector >::iterator grp = variation.begin(); + grp != variation.end(); + ++grp) + { + wxArrayString variants; + + for (std::vector::iterator it = grp->begin(); + it != grp->end(); + ++it) + { + variants.Add(it->c_str()); + } + + m_VariantGroups.push_back(variants); + } + + std::vector selections = *qry.settings->selections; + for (std::vector::iterator sel = selections.begin(); + sel != selections.end(); + ++sel) + { + m_ActorSelections.insert(sel->c_str()); + } + + static_cast*>(this)->NotifyObservers(); } -void ObjectSettings::NotifyObservers() +void ObjectSettings::PostToGame() { - m_ScriptInterface.Eval(_T("Atlas.State.objectSettings.notifyObservers()")); + if (m_SelectedObjects.empty()) + return; + + POST_COMMAND(SetObjectSettings, (m_View, m_SelectedObjects[0], GetSettings())); } diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.h index 71f6160c9a..9d16d34b89 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/ObjectSettings.h @@ -19,37 +19,62 @@ #define INCLUDED_OBJECTSETTINGS #include +#include #include "ScenarioEditor/Tools/Common/MiscState.h" -class ScriptInterface; - namespace AtlasMessage { struct sObjectSettings; } -// This class is now just an interface to the JS Atlas.State.objectSettings, -// for old C++ code that hasn't been ported to JS yet. +// Various settings to be applied to newly created units, or to the currently +// selected unit. If a unit is selected or being previewed, it should match +// these settings. class ObjectSettings { public: - ObjectSettings(Observable >& selectedObjects, ScriptInterface& scriptInterface); - void Init(int view); + ObjectSettings(Observable >& selectedObjects, int view); + size_t GetPlayerID() const; void SetPlayerID(int playerID); + struct Group + { + wxArrayString variants; + wxString chosen; + }; + + const std::vector GetActorVariation() const; + + const std::set& GetActorSelections() const; + void SetActorSelections(const std::set& selections); + // Constructs new sObjectSettings object from settings AtlasMessage::sObjectSettings GetSettings() const; - void NotifyObservers(); - private: - ScriptInterface& m_ScriptInterface; + Observable >& m_SelectedObjects; + + int m_View; + + // 0 = gaia, 1..inf = normal players + size_t m_PlayerID; + + // Set of user-chosen actor selections, potentially a superset of any single + // actor's possible variants (since it doesn't get reset if you select + // a new actor, and will accumulate variant names) + std::set m_ActorSelections; + + // List of actor variant groups (each a list of variant names) + std::vector m_VariantGroups; // Observe changes to unit selection ObservableScopedConnection m_Conn; void OnSelectionChange(const std::vector& selection); + + // Transfer current settings to the currently selected unit (if any) + void PostToGame(); }; #endif // INCLUDED_OBJECTSETTINGS