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