1 #include "OptionsView.h"
2 
3 #include "OptionsController.h"
4 #include "OptionsModel.h"
5 
6 #include <cstdio>
7 #ifdef WIN
8 #include <direct.h>
9 #define getcwd _getcwd
10 #else
11 #include <unistd.h>
12 #endif
13 #include "SDLCompat.h"
14 
15 #include "gui/Style.h"
16 #include "gui/interface/Button.h"
17 #include "gui/interface/Label.h"
18 #include "gui/interface/DropDown.h"
19 #include "gui/interface/Engine.h"
20 #include "gui/interface/Checkbox.h"
21 
22 #include "graphics/Graphics.h"
23 
OptionsView()24 OptionsView::OptionsView():
25 	ui::Window(ui::Point(-1, -1), ui::Point(320, 340)){
26 
27 	auto autowidth = [this](ui::Component *c) {
28 		c->Size.X = Size.X - c->Position.X - 12;
29 	};
30 
31 	ui::Label * tempLabel = new ui::Label(ui::Point(4, 1), ui::Point(Size.X-8, 22), "Simulation Options");
32 	tempLabel->SetTextColour(style::Colour::InformationTitle);
33 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
34 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
35 	autowidth(tempLabel);
36 	AddComponent(tempLabel);
37 
38 	class Separator : public ui::Component
39 	{
40 		public:
41 		Separator(ui::Point position, ui::Point size) : Component(position, size){}
42 		virtual ~Separator(){}
43 
44 		void Draw(const ui::Point& screenPos) override
45 		{
46 			GetGraphics()->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 180);
47 		}
48 	};
49 
50 	Separator *tmpSeparator = new Separator(ui::Point(0, 22), ui::Point(Size.X, 1));
51 	AddComponent(tmpSeparator);
52 
53 	int currentY = 6;
54 	scrollPanel = new ui::ScrollPanel(ui::Point(1, 23), ui::Point(Size.X-2, Size.Y-39));
55 
56 	AddComponent(scrollPanel);
57 
58 	heatSimulation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Heat simulation \bgIntroduced in version 34", "");
59 	autowidth(heatSimulation);
60 	heatSimulation->SetActionCallback({ [this] { c->SetHeatSimulation(heatSimulation->GetChecked()); } });
61 	scrollPanel->AddChild(heatSimulation);
62 	currentY+=14;
63 	tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgCan cause odd behaviour when disabled");
64 	autowidth(tempLabel);
65 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
66 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
67 	scrollPanel->AddChild(tempLabel);
68 
69 	currentY+=16;
70 	ambientHeatSimulation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Ambient heat simulation \bgIntroduced in version 50", "");
71 	autowidth(ambientHeatSimulation);
72 	ambientHeatSimulation->SetActionCallback({ [this] { c->SetAmbientHeatSimulation(ambientHeatSimulation->GetChecked()); } });
73 	scrollPanel->AddChild(ambientHeatSimulation);
74 	currentY+=14;
75 	tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgCan cause odd / broken behaviour with many saves");
76 	autowidth(tempLabel);
77 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
78 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
79 	scrollPanel->AddChild(tempLabel);
80 
81 	currentY+=16;
82 	newtonianGravity = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Newtonian gravity \bgIntroduced in version 48", "");
83 	autowidth(newtonianGravity);
84 	newtonianGravity->SetActionCallback({ [this] { c->SetNewtonianGravity(newtonianGravity->GetChecked()); } });
85 	scrollPanel->AddChild(newtonianGravity);
86 	currentY+=14;
87 	tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgMay cause poor performance on older computers");
88 	autowidth(tempLabel);
89 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
90 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
91 	scrollPanel->AddChild(tempLabel);
92 
93 	currentY+=16;
94 	waterEqualisation = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Water equalisation \bgIntroduced in version 61", "");
95 	autowidth(waterEqualisation);
96 	waterEqualisation->SetActionCallback({ [this] { c->SetWaterEqualisation(waterEqualisation->GetChecked()); } });
97 	scrollPanel->AddChild(waterEqualisation);
98 	currentY+=14;
99 	tempLabel = new ui::Label(ui::Point(24, currentY), ui::Point(1, 16), "\bgMay cause poor performance with a lot of water");
100 	autowidth(tempLabel);
101 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
102 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
103 	scrollPanel->AddChild(tempLabel);
104 
105 	currentY+=19;
106 	airMode = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
107 	scrollPanel->AddChild(airMode);
108 	airMode->AddOption(std::pair<String, int>("On", 0));
109 	airMode->AddOption(std::pair<String, int>("Pressure off", 1));
110 	airMode->AddOption(std::pair<String, int>("Velocity off", 2));
111 	airMode->AddOption(std::pair<String, int>("Off", 3));
112 	airMode->AddOption(std::pair<String, int>("No Update", 4));
113 	airMode->SetActionCallback({ [this] { c->SetAirMode(airMode->GetOption().second); } });
114 
115 	tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Air Simulation Mode");
116 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
117 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
118 	scrollPanel->AddChild(tempLabel);
119 
120 	currentY+=20;
121 	gravityMode = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
122 	scrollPanel->AddChild(gravityMode);
123 	gravityMode->AddOption(std::pair<String, int>("Vertical", 0));
124 	gravityMode->AddOption(std::pair<String, int>("Off", 1));
125 	gravityMode->AddOption(std::pair<String, int>("Radial", 2));
126 	gravityMode->SetActionCallback({ [this] { c->SetGravityMode(gravityMode->GetOption().second); } });
127 
128 	tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Gravity Simulation Mode");
129 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
130 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
131 	scrollPanel->AddChild(tempLabel);
132 
133 	currentY+=20;
134 	edgeMode = new ui::DropDown(ui::Point(Size.X-95, currentY), ui::Point(80, 16));
135 	scrollPanel->AddChild(edgeMode);
136 	edgeMode->AddOption(std::pair<String, int>("Void", 0));
137 	edgeMode->AddOption(std::pair<String, int>("Solid", 1));
138 	edgeMode->AddOption(std::pair<String, int>("Loop", 2));
139 	edgeMode->SetActionCallback({ [this] { c->SetEdgeMode(edgeMode->GetOption().second); } });
140 
141 	tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Edge Mode");
142 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
143 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
144 	scrollPanel->AddChild(tempLabel);
145 
146 	currentY+=20;
147 	tmpSeparator = new Separator(ui::Point(0, currentY), ui::Point(Size.X, 1));
148 	scrollPanel->AddChild(tmpSeparator);
149 
150 	currentY+=4;
151 	scale = new ui::DropDown(ui::Point(8, currentY), ui::Point(40, 16));
152 	{
153 		int current_scale = ui::Engine::Ref().GetScale();
154 		int ix_scale = 1;
155 		bool current_scale_valid = false;
156 		do
157 		{
158 			if (current_scale == ix_scale)
159 				current_scale_valid = true;
160 			scale->AddOption(std::pair<String, int>(String::Build(ix_scale), ix_scale));
161 			ix_scale += 1;
162 		}
163 		while (ui::Engine::Ref().GetMaxWidth() >= ui::Engine::Ref().GetWidth() * ix_scale && ui::Engine::Ref().GetMaxHeight() >= ui::Engine::Ref().GetHeight() * ix_scale);
164 		if (!current_scale_valid)
165 			scale->AddOption(std::pair<String, int>("current", current_scale));
166 	}
167 	scale->SetActionCallback({ [this] { c->SetScale(scale->GetOption().second); } });
168 	scrollPanel->AddChild(scale);
169 
170 	tempLabel = new ui::Label(ui::Point(scale->Position.X+scale->Size.X+3, currentY), ui::Point(Size.X-40, 16), "\bg- Window scale factor for larger screens");
171 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
172 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
173 	scrollPanel->AddChild(tempLabel);
174 
175 	currentY+=20;
176 	resizable = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Resizable", "");
177 	autowidth(resizable);
178 	resizable->SetActionCallback({ [this] { c->SetResizable(resizable->GetChecked()); } });
179 	tempLabel = new ui::Label(ui::Point(resizable->Position.X+Graphics::textwidth(resizable->GetText())+20, currentY), ui::Point(1, 16), "\bg- Allow resizing and maximizing window");
180 	autowidth(tempLabel);
181 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
182 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
183 	scrollPanel->AddChild(tempLabel);
184 	scrollPanel->AddChild(resizable);
185 
186 	currentY+=20;
187 	fullscreen = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Fullscreen", "");
188 	autowidth(fullscreen);
189 	fullscreen->SetActionCallback({ [this] { c->SetFullscreen(fullscreen->GetChecked()); } });
190 	tempLabel = new ui::Label(ui::Point(fullscreen->Position.X+Graphics::textwidth(fullscreen->GetText())+20, currentY), ui::Point(1, 16), "\bg- Fill the entire screen");
191 	autowidth(tempLabel);
192 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
193 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
194 	scrollPanel->AddChild(tempLabel);
195 	scrollPanel->AddChild(fullscreen);
196 
197 	currentY+=20;
198 	altFullscreen = new ui::Checkbox(ui::Point(23, currentY), ui::Point(1, 16), "Change Resolution", "");
199 	autowidth(altFullscreen);
200 	altFullscreen->SetActionCallback({ [this] { c->SetAltFullscreen(altFullscreen->GetChecked()); } });
201 	tempLabel = new ui::Label(ui::Point(altFullscreen->Position.X+Graphics::textwidth(altFullscreen->GetText())+20, currentY), ui::Point(1, 16), "\bg- Set optimial screen resolution");
202 	autowidth(tempLabel);
203 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
204 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
205 	scrollPanel->AddChild(tempLabel);
206 	scrollPanel->AddChild(altFullscreen);
207 
208 	currentY+=20;
209 	forceIntegerScaling = new ui::Checkbox(ui::Point(23, currentY), ui::Point(1, 16), "Force Integer Scaling", "");
210 	autowidth(forceIntegerScaling);
211 	forceIntegerScaling->SetActionCallback({ [this] { c->SetForceIntegerScaling(forceIntegerScaling->GetChecked()); } });
212 	tempLabel = new ui::Label(ui::Point(altFullscreen->Position.X+Graphics::textwidth(forceIntegerScaling->GetText())+20, currentY), ui::Point(1, 16), "\bg- Less blurry");
213 	autowidth(tempLabel);
214 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
215 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
216 	scrollPanel->AddChild(tempLabel);
217 	scrollPanel->AddChild(forceIntegerScaling);
218 
219 	currentY+=20;
220 	fastquit = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Fast Quit", "");
221 	autowidth(fastquit);
222 	fastquit->SetActionCallback({ [this] { c->SetFastQuit(fastquit->GetChecked()); } });
223 	tempLabel = new ui::Label(ui::Point(fastquit->Position.X+Graphics::textwidth(fastquit->GetText())+20, currentY), ui::Point(1, 16), "\bg- Always exit completely when hitting close");
224 	autowidth(tempLabel);
225 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
226 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
227 	scrollPanel->AddChild(tempLabel);
228 	scrollPanel->AddChild(fastquit);
229 
230 	currentY+=20;
231 	showAvatars = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Show Avatars", "");
232 	autowidth(showAvatars);
233 	showAvatars->SetActionCallback({ [this] { c->SetShowAvatars(showAvatars->GetChecked()); } });
234 	tempLabel = new ui::Label(ui::Point(showAvatars->Position.X+Graphics::textwidth(showAvatars->GetText())+20, currentY), ui::Point(1, 16), "\bg- Disable if you have a slow connection");
235 	autowidth(tempLabel);
236 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
237 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
238 	scrollPanel->AddChild(tempLabel);
239 	scrollPanel->AddChild(showAvatars);
240 
241 	currentY+=20;
242 	mouseClickRequired = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Sticky Categories", "");
243 	autowidth(mouseClickRequired);
244 	mouseClickRequired->SetActionCallback({ [this] { c->SetMouseClickrequired(mouseClickRequired->GetChecked()); } });
245 	tempLabel = new ui::Label(ui::Point(mouseClickRequired->Position.X+Graphics::textwidth(mouseClickRequired->GetText())+20, currentY), ui::Point(1, 16), "\bg- Switch between categories by clicking");
246 	autowidth(tempLabel);
247 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
248 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
249 	scrollPanel->AddChild(tempLabel);
250 	scrollPanel->AddChild(mouseClickRequired);
251 
252 	currentY+=20;
253 	includePressure = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Include Pressure", "");
254 	autowidth(includePressure);
255 	includePressure->SetActionCallback({ [this] { c->SetIncludePressure(includePressure->GetChecked()); } });
256 	tempLabel = new ui::Label(ui::Point(includePressure->Position.X+Graphics::textwidth(includePressure->GetText())+20, currentY), ui::Point(1, 16), "\bg- When saving, copying, stamping, etc.");
257 	autowidth(tempLabel);
258 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
259 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
260 	scrollPanel->AddChild(tempLabel);
261 	scrollPanel->AddChild(includePressure);
262 
263 	currentY+=20;
264 	perfectCirclePressure = new ui::Checkbox(ui::Point(8, currentY), ui::Point(1, 16), "Perfect Circle", "");
265 	autowidth(perfectCirclePressure);
266 	perfectCirclePressure->SetActionCallback({ [this] { c->SetPerfectCircle(perfectCirclePressure->GetChecked()); } });
267 	tempLabel = new ui::Label(ui::Point(perfectCirclePressure->Position.X+Graphics::textwidth(perfectCirclePressure->GetText())+20, currentY), ui::Point(1, 16), "\bg- Better circle brush, without incorrect points on edges");
268 	autowidth(tempLabel);
269 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
270 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
271 	scrollPanel->AddChild(tempLabel);
272 	scrollPanel->AddChild(perfectCirclePressure);
273 
274 	//perfectCirclePressure
275 
276 	currentY+=20;
277 	decoSpace = new ui::DropDown(ui::Point(8, currentY), ui::Point(60, 16));
278 	decoSpace->SetActionCallback({ [this] { c->SetDecoSpace(decoSpace->GetOption().second); } });
279 	scrollPanel->AddChild(decoSpace);
280 	decoSpace->AddOption(std::pair<String, int>("sRGB", 0));
281 	decoSpace->AddOption(std::pair<String, int>("Linear", 1));
282 	decoSpace->AddOption(std::pair<String, int>("Gamma 2.2", 2));
283 	decoSpace->AddOption(std::pair<String, int>("Gamma 1.8", 3));
284 
285 	tempLabel = new ui::Label(ui::Point(decoSpace->Position.X+decoSpace->Size.X+3, currentY), ui::Point(Size.X-40, 16), "\bg- Colour space used by decoration tools");
286 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
287 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
288 	scrollPanel->AddChild(tempLabel);
289 
290 	currentY+=20;
291 	ui::Button * dataFolderButton = new ui::Button(ui::Point(8, currentY), ui::Point(90, 16), "Open Data Folder");
292 	dataFolderButton->SetActionCallback({ [] {
293 //one of these should always be defined
294 #ifdef WIN
295 		const char* openCommand = "explorer ";
296 #elif MACOSX
297 		const char* openCommand = "open ";
298 //#elif LIN
299 #else
300 		const char* openCommand = "xdg-open ";
301 #endif
302 		char* workingDirectory = new char[FILENAME_MAX+strlen(openCommand)];
303 		sprintf(workingDirectory, "%s\"%s\"", openCommand, getcwd(NULL, 0));
304 		system(workingDirectory);
305 		delete[] workingDirectory;
306 	} });
307 	scrollPanel->AddChild(dataFolderButton);
308 
309 	tempLabel = new ui::Label(ui::Point(dataFolderButton->Position.X+dataFolderButton->Size.X+3, currentY), ui::Point(1, 16), "\bg- Open the data and preferences folder");
310 	autowidth(tempLabel);
311 	tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
312 	tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
313 	scrollPanel->AddChild(tempLabel);
314 
315 	ui::Button * tempButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK");
316 	tempButton->SetActionCallback({ [this] { c->Exit(); } });
317 	AddComponent(tempButton);
318 	SetCancelButton(tempButton);
319 	SetOkayButton(tempButton);
320 	currentY+=20;
321 	scrollPanel->InnerSize = ui::Point(Size.X, currentY);
322 }
323 
NotifySettingsChanged(OptionsModel * sender)324 void OptionsView::NotifySettingsChanged(OptionsModel * sender)
325 {
326 	heatSimulation->SetChecked(sender->GetHeatSimulation());
327 	ambientHeatSimulation->SetChecked(sender->GetAmbientHeatSimulation());
328 	newtonianGravity->SetChecked(sender->GetNewtonianGravity());
329 	waterEqualisation->SetChecked(sender->GetWaterEqualisation());
330 	airMode->SetOption(sender->GetAirMode());
331 	gravityMode->SetOption(sender->GetGravityMode());
332 	decoSpace->SetOption(sender->GetDecoSpace());
333 	edgeMode->SetOption(sender->GetEdgeMode());
334 	scale->SetOption(sender->GetScale());
335 	resizable->SetChecked(sender->GetResizable());
336 	fullscreen->SetChecked(sender->GetFullscreen());
337 	altFullscreen->SetChecked(sender->GetAltFullscreen());
338 	forceIntegerScaling->SetChecked(sender->GetForceIntegerScaling());
339 	fastquit->SetChecked(sender->GetFastQuit());
340 	showAvatars->SetChecked(sender->GetShowAvatars());
341 	mouseClickRequired->SetChecked(sender->GetMouseClickRequired());
342 	includePressure->SetChecked(sender->GetIncludePressure());
343 	perfectCirclePressure->SetChecked(sender->GetPerfectCircle());
344 }
345 
AttachController(OptionsController * c_)346 void OptionsView::AttachController(OptionsController * c_)
347 {
348 	c = c_;
349 }
350 
OnDraw()351 void OptionsView::OnDraw()
352 {
353 	Graphics * g = GetGraphics();
354 	g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3);
355 	g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 255, 255, 255, 255);
356 }
357 
OnTryExit(ExitMethod method)358 void OptionsView::OnTryExit(ExitMethod method)
359 {
360 	c->Exit();
361 }
362 
363 
~OptionsView()364 OptionsView::~OptionsView() {
365 }
366