void ObjectBottomBar::OnFirstDisplay() { // We use messages here because the simulation is not init'd otherwise (causing a crash) // Get player names wxArrayString players; AtlasMessage::qGetPlayerDefaults qryPlayers; qryPlayers.Post(); AtObj playerData = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qryPlayers.defaults); AtObj playerDefs = *playerData["PlayerData"]; for (AtIter p = playerDefs["item"]; p.defined(); ++p) { players.Add(wxString(p["Name"])); } wxDynamicCast(FindWindow(ID_PlayerSelect), PlayerComboBox)->SetPlayers(players); // Initialise the game with the default settings POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"wireframe", m_ViewerWireframe)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"walk", m_ViewerMove)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"ground", m_ViewerGround)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"shadows", m_ViewerShadows)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"stats", m_ViewerPolyCount)); POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::ACTOR, L"bounding_box", m_ViewerBoundingBox)); POST_MESSAGE(SetViewParamI, (AtlasMessage::eRenderView::ACTOR, L"prop_points", m_ViewerPropPointsMode)); }
void MapSidebar::OnFirstDisplay() { // We do this here becase messages are used which requires simulation to be init'd m_MapSettingsCtrl->CreateWidgets(); m_MapSettingsCtrl->ReadFromEngine(); // Load the map sizes list AtlasMessage::qGetMapSizes qrySizes; qrySizes.Post(); AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes); wxChoice* sizeChoice = wxDynamicCast(FindWindow(ID_RandomSize), wxChoice); for (AtIter s = sizes["Data"]["item"]; s.defined(); ++s) { long tiles = 0; wxString(s["Tiles"]).ToLong(&tiles); sizeChoice->Append(wxString(s["Name"]), (void*)(intptr_t)tiles); } sizeChoice->SetSelection(0); // Load the RMS script list AtlasMessage::qGetRMSData qry; qry.Post(); std::vector<std::string> scripts = *qry.data; wxChoice* scriptChoice = wxDynamicCast(FindWindow(ID_RandomScript), wxChoice); scriptChoice->Clear(); for (size_t i = 0; i < scripts.size(); ++i) { AtObj data = AtlasObject::LoadFromJSON(scripts[i]); wxString name(data["settings"]["Name"]); scriptChoice->Append(name, new AtObjClientData(*data["settings"])); } scriptChoice->SetSelection(0); Layout(); }
void TerrainSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt)) { wxArrayString sizeNames; std::vector<size_t> sizeTiles; // Load the map sizes list AtlasMessage::qGetMapSizes qrySizes; qrySizes.Post(); AtObj sizes = AtlasObject::LoadFromJSON(m_ScenarioEditor.GetScriptInterface().GetContext(), *qrySizes.sizes); for (AtIter s = sizes["Sizes"]["item"]; s.defined(); ++s) { long tiles = 0; wxString(s["Tiles"]).ToLong(&tiles); sizeNames.Add(wxString(s["Name"])); sizeTiles.push_back((size_t)tiles); } // TODO: set default based on current map size wxSingleChoiceDialog dlg(this, _("Select new map size. WARNING: This probably only works reliably on blank maps."), _("Resize map"), sizeNames); if (dlg.ShowModal() != wxID_OK) return; size_t tiles = sizeTiles.at(dlg.GetSelection()); POST_COMMAND(ResizeMap, (tiles)); }
void ActorEditorListCtrl::DoImport(AtObj& in) { DeleteData(); for (AtIter group = in["group"]; group.defined(); ++group) { for (AtIter variant = group["variant"]; variant.defined(); ++variant) AddRow(variant); AtObj blank; AddRow(blank); } UpdateDisplay(); }
void MapSettingsControl::ReadFromEngine() { AtlasMessage::qGetMapSettings qry; qry.Post(); if (!(*qry.settings).empty()) { // Prevent error if there's no map settings to parse m_MapSettings = AtlasObject::LoadFromJSON(*qry.settings); } // map name wxDynamicCast(FindWindow(ID_MapName), wxTextCtrl)->ChangeValue(wxString(m_MapSettings["Name"])); // map description wxDynamicCast(FindWindow(ID_MapDescription), wxTextCtrl)->ChangeValue(wxString(m_MapSettings["Description"])); // map preview wxDynamicCast(FindWindow(ID_MapPreview), wxTextCtrl)->ChangeValue(wxString(m_MapSettings["Preview"])); // reveal map wxDynamicCast(FindWindow(ID_MapReveal), wxCheckBox)->SetValue(wxString(m_MapSettings["RevealMap"]) == L"true"); // game type / victory conditions if (m_MapSettings["GameType"].defined()) wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetStringSelection(wxString(m_MapSettings["GameType"])); else wxDynamicCast(FindWindow(ID_MapType), wxChoice)->SetSelection(0); // lock teams wxDynamicCast(FindWindow(ID_MapTeams), wxCheckBox)->SetValue(wxString(m_MapSettings["LockTeams"]) == L"true"); // keywords { m_MapSettingsKeywords.clear(); for (AtIter keyword = m_MapSettings["Keywords"]["item"]; keyword.defined(); ++keyword) m_MapSettingsKeywords.insert(std::wstring(keyword)); wxDynamicCast(FindWindow(ID_MapKW_Demo), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"demo") != 0); wxDynamicCast(FindWindow(ID_MapKW_Naval), wxCheckBox)->SetValue(m_MapSettingsKeywords.count(L"naval") != 0); } }
void PlayerSettingsControl::ReadFromEngine() { AtlasMessage::qGetMapSettings qry; qry.Post(); if (!(*qry.settings).empty()) { // Prevent error if there's no map settings to parse m_MapSettings = AtlasObject::LoadFromJSON(*qry.settings); } else { // Use blank object, it will be created next m_MapSettings = AtObj(); } AtIter player = m_MapSettings["PlayerData"]["item"]; if (!m_MapSettings.defined() || !player.defined() || player.count() == 0) { // Player data missing - set number of players to max m_NumPlayers = MAX_NUM_PLAYERS; } else m_NumPlayers = player.count(); wxASSERT(m_NumPlayers <= MAX_NUM_PLAYERS && m_NumPlayers != 0); // To prevent recursion, don't handle GUI events right now m_InGUIUpdate = true; wxDynamicCast(FindWindow(ID_NumPlayers), wxSpinCtrl)->SetValue(m_NumPlayers); // Remove / add extra player pages as needed m_Players->ResizePlayers(m_NumPlayers); // Update player controls with player data AtIter playerDefs = m_PlayerDefaults["item"]; if (playerDefs.defined()) ++playerDefs; // skip gaia for (size_t i = 0; i < MAX_NUM_PLAYERS; ++i) { const PlayerPageControls& controls = m_PlayerControls[i]; // name wxString name(_("Unknown")); bool defined = player["Name"].defined(); if (defined) name = wxString(player["Name"]); else if (playerDefs["Name"].defined()) name = wxString(playerDefs["Name"]); controls.name->SetValue(name); wxDynamicCast(FindWindowById(ID_DefaultName, controls.page), DefaultCheckbox)->SetValue(defined); // civ wxChoice* choice = controls.civ; wxString civCode; defined = player["Civ"].defined(); if (defined) civCode = wxString(player["Civ"]); else civCode = wxString(playerDefs["Civ"]); for (size_t j = 0; j < choice->GetCount(); ++j) { wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(j)); if (str->GetData() == civCode) { choice->SetSelection(j); break; } } wxDynamicCast(FindWindowById(ID_DefaultCiv, controls.page), DefaultCheckbox)->SetValue(defined); // colour wxColour colour; AtObj clrObj = *player["Colour"]; defined = clrObj.defined(); if (!defined) clrObj = *playerDefs["Colour"]; colour = wxColor((*clrObj["r"]).getInt(), (*clrObj["g"]).getInt(), (*clrObj["b"]).getInt()); controls.colour->SetBackgroundColour(colour); wxDynamicCast(FindWindowById(ID_DefaultColour, controls.page), DefaultCheckbox)->SetValue(defined); // player type wxString aiID; defined = player["AI"].defined(); if (defined) aiID = wxString(player["AI"]); else aiID = wxString(playerDefs["AI"]); choice = controls.ai; if (!aiID.empty()) { // AI for (size_t j = 0; j < choice->GetCount(); ++j) { wxStringClientData* str = dynamic_cast<wxStringClientData*>(choice->GetClientObject(j)); if (str->GetData() == aiID) { choice->SetSelection(j); break; } } } else // Human choice->SetSelection(0); wxDynamicCast(FindWindowById(ID_DefaultAI, controls.page), DefaultCheckbox)->SetValue(defined); // resources AtObj resObj = *player["Resources"]; defined = resObj.defined() && resObj["food"].defined(); if (defined) controls.food->SetValue(wxString(resObj["food"])); else controls.food->SetValue(0); wxDynamicCast(FindWindowById(ID_DefaultFood, controls.page), DefaultCheckbox)->SetValue(defined); defined = resObj.defined() && resObj["wood"].defined(); if (defined) controls.wood->SetValue(wxString(resObj["wood"])); else controls.wood->SetValue(0); wxDynamicCast(FindWindowById(ID_DefaultWood, controls.page), DefaultCheckbox)->SetValue(defined); defined = resObj.defined() && resObj["metal"].defined(); if (defined) controls.metal->SetValue(wxString(resObj["metal"])); else controls.metal->SetValue(0); wxDynamicCast(FindWindowById(ID_DefaultMetal, controls.page), DefaultCheckbox)->SetValue(defined); defined = resObj.defined() && resObj["stone"].defined(); if (defined) controls.stone->SetValue(wxString(resObj["stone"])); else controls.stone->SetValue(0); wxDynamicCast(FindWindowById(ID_DefaultStone, controls.page), DefaultCheckbox)->SetValue(defined); // population limit defined = player["PopulationLimit"].defined(); if (defined) controls.pop->SetValue(wxString(player["PopulationLimit"])); else controls.pop->SetValue(0); wxDynamicCast(FindWindowById(ID_DefaultPop, controls.page), DefaultCheckbox)->SetValue(defined); // team defined = player["Team"].defined(); if (defined) controls.team->SetSelection((*player["Team"]).getInt() + 1); else controls.team->SetSelection(0); wxDynamicCast(FindWindowById(ID_DefaultTeam, controls.page), DefaultCheckbox)->SetValue(defined); // camera if (player["StartingCamera"].defined()) { sCameraInfo info; // Don't use wxAtof because it depends on locales which // may cause problems with decimal points // see: http://www.wxwidgets.org/docs/faqgtk.htm#locale AtObj camPos = *player["StartingCamera"]["Position"]; info.pX = (float)(*camPos["x"]).getDouble(); info.pY = (float)(*camPos["y"]).getDouble(); info.pZ = (float)(*camPos["z"]).getDouble(); AtObj camRot = *player["StartingCamera"]["Rotation"]; info.rX = (float)(*camRot["x"]).getDouble(); info.rY = (float)(*camRot["y"]).getDouble(); info.rZ = (float)(*camRot["z"]).getDouble(); controls.page->SetCamera(info, true); } else controls.page->SetCamera(sCameraInfo(), false); // Only increment AtIters if they are defined if (player.defined()) ++player; if (playerDefs.defined()) ++playerDefs; } // Send default properties to engine, since they might not be set SendToEngine(); m_InGUIUpdate = false; }
void PlayerSettingsControl::CreateWidgets() { // To prevent recursion, don't handle GUI events right now m_InGUIUpdate = true; // Load default civ and player data wxArrayString civNames; wxArrayString civCodes; AtlasMessage::qGetCivData qryCiv; qryCiv.Post(); std::vector<std::string> civData = *qryCiv.data; for (size_t i = 0; i < civData.size(); ++i) { AtObj civ = AtlasObject::LoadFromJSON(civData[i]); civNames.Add(wxString(civ["Name"])); civCodes.Add(wxString(civ["Code"])); } // Load AI data ArrayOfAIData ais(AIData::CompareAIData); AtlasMessage::qGetAIData qryAI; qryAI.Post(); AtObj aiData = AtlasObject::LoadFromJSON(*qryAI.data); for (AtIter a = aiData["AIData"]["item"]; a.defined(); ++a) { ais.Add(new AIData(wxString(a["id"]), wxString(a["data"]["name"]))); } // Create player pages AtIter playerDefs = m_PlayerDefaults["item"]; if (playerDefs.defined()) ++playerDefs; // Skip gaia for (size_t i = 0; i < MAX_NUM_PLAYERS; ++i) { // Create new player tab and get controls wxString name(_("Unknown")); if (playerDefs["Name"].defined()) name = playerDefs["Name"]; PlayerPageControls controls = m_Players->AddPlayer(name, i); m_PlayerControls.push_back(controls); // Populate civ choice box wxChoice* civChoice = controls.civ; for (size_t j = 0; j < civNames.Count(); ++j) civChoice->Append(civNames[j], new wxStringClientData(civCodes[j])); civChoice->SetSelection(0); // Populate ai choice box wxChoice* aiChoice = controls.ai; aiChoice->Append(_("<None>"), new wxStringClientData()); for (size_t j = 0; j < ais.Count(); ++j) aiChoice->Append(ais[j]->GetName(), new wxStringClientData(ais[j]->GetID())); aiChoice->SetSelection(0); // Only increment AtIters if they are defined if (playerDefs.defined()) ++playerDefs; } m_InGUIUpdate = false; }
ObjectBottomBar::ObjectBottomBar( wxWindow* parent, ScenarioEditor& scenarioEditor, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings, ObjectSidebarImpl* p ) : wxPanel(parent, wxID_ANY), p(p), m_ScenarioEditor(scenarioEditor) { m_ViewerWireframe = false; m_ViewerMove = false; m_ViewerGround = true; m_ViewerShadows = true; m_ViewerPolyCount = false; m_ViewerBoundingBox = false; m_ViewerAxesMarker = false; m_ViewerPropPointsMode = 0; wxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL); // --- viewer options panel ------------------------------------------------------------------------------- m_ViewerPanel = new wxPanel(this, wxID_ANY); wxSizer* viewerSizer = new wxBoxSizer(wxHORIZONTAL); wxSizer* viewerButtonsSizer = new wxStaticBoxSizer(wxHORIZONTAL, m_ViewerPanel, _("Display settings")); { wxSizer* viewerButtonsLeft = new wxBoxSizer(wxVERTICAL); viewerButtonsLeft->SetMinSize(110, -1); viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerWireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand()); viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerMove, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand()); viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerGround, _("Ground")), _("Toggle the ground plane")), wxSizerFlags().Expand()); viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand()); 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()); viewerButtonsLeft->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerBoundingBox, _("Bounding Boxes")), _("Toggle bounding boxes")), wxSizerFlags().Expand()); wxSizer* viewerButtonsRight = new wxBoxSizer(wxVERTICAL); viewerButtonsRight->SetMinSize(110,-1); viewerButtonsRight->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerAxesMarker, _("Axes Marker")), _("Toggle the axes marker (R=X, G=Y, B=Z)")), wxSizerFlags().Expand()); viewerButtonsRight->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerPropPoints, _("Prop Points")), _("Toggle prop points (works best in wireframe mode)")), wxSizerFlags().Expand()); viewerButtonsSizer->Add(viewerButtonsLeft, wxSizerFlags().Expand()); viewerButtonsSizer->Add(viewerButtonsRight, wxSizerFlags().Expand()); } viewerSizer->Add(viewerButtonsSizer, wxSizerFlags().Expand()); viewerSizer->AddSpacer(3); // --- animations panel ------------------------------------------------------------------------------- wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation")); // TODO: this list should come from the actor wxArrayString animChoices; AtObj anims (Datafile::ReadList("animations")); for (AtIter a = anims["item"]; a.defined(); ++a) { animChoices.Add(wxString(*a)); } wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, animChoices); viewerAnimSelector->SetSelection(0); viewerAnimSizer->Add(viewerAnimSelector, wxSizerFlags().Expand()); wxSizer* viewerAnimSpeedSizer = new wxBoxSizer(wxHORIZONTAL); viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerPlay, _("Play"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand()); viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerPause, _("Pause"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand()); viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerSlow, _("Slow"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand()); viewerAnimSizer->Add(viewerAnimSpeedSizer); viewerSizer->Add(viewerAnimSizer, wxSizerFlags().Expand()); // --- add viewer-specific options ------------------------------------------------------------------------------- m_ViewerPanel->SetSizer(viewerSizer); mainSizer->Add(m_ViewerPanel, wxSizerFlags().Expand()); m_ViewerPanel->Layout(); // prevents strange visibility glitch of the animation buttons on my machine (Vista 32-bit SP1) -- vtsj m_ViewerPanel->Show(false); // --- add player/variation selection ------------------------------------------------------------------------------- wxSizer* playerSelectionSizer = new wxBoxSizer(wxHORIZONTAL); wxSizer* playerVariationSizer = new wxBoxSizer(wxVERTICAL); // TODO: make this a wxChoice instead wxComboBox* playerSelect = new PlayerComboBox(this, objectSettings, mapSettings); playerSelectionSizer->Add(new wxStaticText(this, wxID_ANY, _("Player:")), wxSizerFlags().Align(wxALIGN_CENTER)); playerSelectionSizer->AddSpacer(3); playerSelectionSizer->Add(playerSelect); playerVariationSizer->Add(playerSelectionSizer); playerVariationSizer->AddSpacer(3); 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()); playerVariationSizer->Add(variationSizer, wxSizerFlags().Proportion(1)); mainSizer->AddSpacer(3); mainSizer->Add(playerVariationSizer, wxSizerFlags().Expand()); // ---------------------------------------------------------------------------------- SetSizer(mainSizer); }
ObjectBottomBar::ObjectBottomBar(wxWindow* parent, ScenarioEditor& scenarioEditor, Observable<ObjectSettings>& objectSettings, Observable<AtObj>& mapSettings, ObjectSidebarImpl* p) : wxPanel(parent, wxID_ANY), p(p), m_ScenarioEditor(scenarioEditor) { m_ViewerWireframe = false; m_ViewerMove = false; m_ViewerGround = true; m_ViewerShadows = true; m_ViewerPolyCount = false; wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); m_ViewerPanel = new wxPanel(this, wxID_ANY); wxSizer* viewerSizer = new wxBoxSizer(wxHORIZONTAL); wxSizer* viewerButtonsSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Display settings")); viewerButtonsSizer->SetMinSize(140, -1); viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerWireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand()); viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerMove, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand()); viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerGround, _("Ground")), _("Toggle the ground plane")), wxSizerFlags().Expand()); viewerButtonsSizer->Add(Tooltipped(new wxButton(m_ViewerPanel, ID_ViewerShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand()); viewerButtonsSizer->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()); viewerSizer->Add(viewerButtonsSizer, wxSizerFlags().Expand()); wxSizer* viewerAnimSizer = new wxStaticBoxSizer(wxVERTICAL, m_ViewerPanel, _("Animation")); // TODO: this list should come from the actor wxArrayString animChoices; AtObj anims (Datafile::ReadList("animations")); for (AtIter a = anims["item"]; a.defined(); ++a) { animChoices.Add(wxString(*a)); } wxChoice* viewerAnimSelector = new wxChoice(m_ViewerPanel, ID_ViewerAnimation, wxDefaultPosition, wxDefaultSize, animChoices); viewerAnimSelector->SetSelection(0); viewerAnimSizer->Add(viewerAnimSelector, wxSizerFlags().Expand()); wxSizer* viewerAnimSpeedSizer = new wxBoxSizer(wxHORIZONTAL); viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerPlay, _("Play"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand()); viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerPause, _("Pause"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand()); viewerAnimSpeedSizer->Add(new wxButton(m_ViewerPanel, ID_ViewerSlow, _("Slow"), wxDefaultPosition, wxSize(50, -1)), wxSizerFlags().Expand()); viewerAnimSizer->Add(viewerAnimSpeedSizer); viewerSizer->Add(viewerAnimSizer, wxSizerFlags().Expand()); m_ViewerPanel->SetSizer(viewerSizer); sizer->Add(m_ViewerPanel, wxSizerFlags().Expand()); m_ViewerPanel->Show(false); wxSizer* playerVariationSizer = new wxBoxSizer(wxVERTICAL); // TODO: make this a wxChoice instead wxComboBox* playerSelect = new PlayerComboBox(this, objectSettings, mapSettings); playerVariationSizer->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()); playerVariationSizer->Add(variationSizer, wxSizerFlags().Proportion(1)); sizer->Add(playerVariationSizer, wxSizerFlags().Expand()); SetSizer(sizer); }