1 /* Copyright (C) 2011 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 "VariationControl.h"
21 
22 #include "ScenarioEditor/Tools/Common/ObjectSettings.h"
23 
VariationControl(wxWindow * parent,Observable<ObjectSettings> & objectSettings)24 VariationControl::VariationControl(wxWindow* parent, Observable<ObjectSettings>& objectSettings)
25 : wxScrolledWindow(parent, -1),
26 m_ObjectSettings(objectSettings)
27 {
28 	m_Conn = m_ObjectSettings.RegisterObserver(1, &VariationControl::OnObjectSettingsChange, this);
29 
30 	SetScrollRate(0, 5);
31 
32 	m_Sizer = new wxBoxSizer(wxVERTICAL);
33 	SetSizer(m_Sizer);
34 }
35 
36 // Event handler shared by all the combo boxes created by this window
OnSelect(wxCommandEvent & evt)37 void VariationControl::OnSelect(wxCommandEvent& evt)
38 {
39 	std::set<wxString> selections;
40 
41 	// It's possible for a variant name to appear in multiple groups.
42 	// If so, assume that all the names in each group are the same, so
43 	// we don't have to worry about some impossible combinations (e.g.
44 	// one group "a,b", a second "b,c", and a third "c,a", where's there's
45 	// no set of selections that matches one (and only one) of each group).
46 	//
47 	// So... When a combo box is changed from 'a' to 'b', add 'b' to the new
48 	// selections and make sure any other combo boxes containing both 'a' and
49 	// 'b' no longer contain 'a'.
50 
51 	wxComboBox* thisComboBox = wxDynamicCast(evt.GetEventObject(), wxComboBox);
52 	wxCHECK(thisComboBox != NULL, );
53 	wxString newValue = thisComboBox->GetValue();
54 
55 	selections.insert(newValue);
56 
57 	for (size_t i = 0; i < m_ComboBoxes.size(); ++i)
58 	{
59 		wxComboBox* comboBox = m_ComboBoxes[i];
60 		// If our newly selected value is used in another combobox, we want
61 		// that combobox to use the new value, so don't add its old value
62 		// to the list of selections
63 		if (comboBox->FindString(newValue) == wxNOT_FOUND)
64 			selections.insert(comboBox->GetValue());
65 	}
66 
67 	m_ObjectSettings.SetActorSelections(selections);
68 	m_ObjectSettings.NotifyObserversExcept(m_Conn);
69 	RefreshObjectSettings();
70 }
71 
OnObjectSettingsChange(const ObjectSettings & settings)72 void VariationControl::OnObjectSettingsChange(const ObjectSettings& settings)
73 {
74 	Freeze();
75 
76 	const std::vector<ObjectSettings::Group>& variation = settings.GetActorVariation();
77 
78 	// Creating combo boxes seems to be pretty expensive - so we create as
79 	// few as possible, by never deleting any.
80 
81 	size_t oldCount = m_ComboBoxes.size();
82 	size_t newCount = variation.size();
83 
84 	// If we have too many combo boxes, hide the excess ones
85 	for (size_t i = newCount; i < oldCount; ++i)
86 	{
87 		m_ComboBoxes[i]->Show(false);
88 	}
89 
90 	for (size_t i = 0; i < variation.size(); ++i)
91 	{
92 		const ObjectSettings::Group& group = variation[i];
93 
94 		if (i < oldCount)
95 		{
96 			// Already got enough boxes available, so use an old one
97 			wxComboBox* comboBox = m_ComboBoxes[i];
98 			// Replace the contents of the old combobox with the new data
99 			comboBox->Freeze();
100 			comboBox->Clear();
101 			comboBox->Append(group.variants);
102 			comboBox->SetValue(group.chosen);
103 			comboBox->Show(true);
104 			comboBox->Thaw();
105 		}
106 		else
107 		{
108 			// Create an initially empty combobox, because we can fill it
109 			// quicker than the default constructor can
110 			wxComboBox* combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition,
111 				wxSize(80, wxDefaultCoord), wxArrayString(), wxCB_READONLY);
112 			// Freeze it before adding all the values
113 			combo->Freeze();
114 			combo->Append(group.variants);
115 			combo->SetValue(group.chosen);
116 			combo->Thaw();
117 			// Add the on-select event handler
118 			combo->Connect(wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED,
119 				wxCommandEventHandler(VariationControl::OnSelect), NULL, this);
120 			// Add box to sizer and list
121 			m_Sizer->Add(combo, wxSizerFlags().Expand());
122 			m_ComboBoxes.push_back(combo);
123 		}
124 	}
125 
126 	Layout();
127 
128 	Thaw();
129 
130 	// Make the scrollbars appear when appropriate
131 	FitInside();
132 }
133 
RefreshObjectSettings()134 void VariationControl::RefreshObjectSettings()
135 {
136 	const std::vector<ObjectSettings::Group>& variation = m_ObjectSettings.GetActorVariation();
137 
138 	// For each group, set the corresponding combobox's value to the chosen one
139 	size_t i = 0;
140 	for (std::vector<ObjectSettings::Group>::const_iterator group = variation.begin();
141 		group != variation.end() && i < m_ComboBoxes.size();
142 		++group, ++i)
143 	{
144 		m_ComboBoxes[i]->SetValue(group->chosen);
145 	}
146 }
147