1 /*
2 * This file is part of the Colobot: Gold Edition source code
3 * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
4 * http://epsitec.ch; http://colobot.info; http://github.com/colobot
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see http://gnu.org/licenses
18 */
19
20 #include "ui/screen/screen_setup_controls.h"
21
22 #include "app/app.h"
23
24 #include "common/settings.h"
25
26 #include "ui/controls/button.h"
27 #include "ui/controls/check.h"
28 #include "ui/controls/editvalue.h"
29 #include "ui/controls/group.h"
30 #include "ui/controls/interface.h"
31 #include "ui/controls/key.h"
32 #include "ui/controls/label.h"
33 #include "ui/controls/list.h"
34 #include "ui/controls/scroll.h"
35 #include "ui/controls/window.h"
36
37 namespace Ui
38 {
39
40 const int KEY_VISIBLE = 8; // number of visible keys redefinable
41
CScreenSetupControls()42 CScreenSetupControls::CScreenSetupControls()
43 {
44 m_input = CInput::GetInstancePointer();
45 }
46
SetActive()47 void CScreenSetupControls::SetActive()
48 {
49 m_tab = PHASE_SETUPc;
50 }
51
CreateInterface()52 void CScreenSetupControls::CreateInterface()
53 {
54 CWindow* pw;
55 CLabel* pl;
56 CCheck* pc;
57 CScroll* ps;
58 CButton* pb;
59 CGroup* pg;
60 CList* pli;
61 CEditValue* pev;
62 Math::Point pos, ddim;
63 std::string name;
64
65 CScreenSetup::CreateInterface();
66 pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
67 if ( pw == nullptr ) return;
68
69 pos.x = ox+sx*3;
70 pos.y = 320.0f/480.0f;
71 ddim.x = dim.x*15.0f;
72 ddim.y = 18.0f/480.0f;
73 GetResource(RES_TEXT, RT_SETUP_KEY1, name);
74 pl = pw->CreateLabel(pos, ddim, 0, EVENT_INTERFACE_KINFO1, name);
75 pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
76
77 pos.x = ox+sx*3;
78 pos.y = 302.0f/480.0f;
79 ddim.x = dim.x*15.0f;
80 ddim.y = 18.0f/480.0f;
81 GetResource(RES_TEXT, RT_SETUP_KEY2, name);
82 pl = pw->CreateLabel(pos, ddim, 0, EVENT_INTERFACE_KINFO2, name);
83 pl->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
84
85 ddim.x = 273.0f/640.0f;
86 ddim.y = 168.0f/480.0f;
87 pos.x = 105.0f/640.0f;
88 pos.y = 124.0f/480.0f;
89 pg = pw->CreateGroup(pos, ddim, 0, EVENT_INTERFACE_KGROUP);
90 pg->ClearState(STATE_ENABLE);
91 pg->SetState(STATE_DEAD);
92 pg->SetState(STATE_SHADOW);
93
94 ddim.x = 18.0f/640.0f;
95 ddim.y = (20.0f/480.0f)*KEY_VISIBLE;
96 pos.x = 355.0f/640.0f;
97 pos.y = 128.0f/480.0f;
98 ps = pw->CreateScroll(pos, ddim, -1, EVENT_INTERFACE_KSCROLL);
99 ps->SetVisibleRatio(static_cast<float>(KEY_VISIBLE/INPUT_SLOT_MAX));
100 ps->SetArrowStep(1.0f/(static_cast<float>(INPUT_SLOT_MAX-KEY_VISIBLE)));
101 UpdateKey();
102
103 ddim.x = 160.0f/640.0f;
104 ddim.y = 80.0f/480.0f;
105 pos.x = 400.0f/640.0f;
106 pos.y = 273.0f/480.0f;
107 pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK);
108 pli->SetState(STATE_SHADOW);
109
110 ddim.x = dim.x*1.5f;
111 ddim.y = 18.0f/480.0f;
112 pos.y = 240.0f/480.0f;
113
114 auto CreateJoystickControls = [&](const std::string& label, EventType bindingControl, EventType invertControl)
115 {
116 pos.y -= 20.0f/480.0f;
117 pos.x = 390.0f/640.0f;
118 pos.y -= 5.0f/480.0f;
119 pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, label);
120 pos.y += 5.0f/480.0f;
121 pos.x = 442.0f/640.0f;
122 pev = pw->CreateEditValue(pos, ddim, 0, bindingControl);
123 pev->SetState(STATE_SHADOW);
124 pev->SetType(EVT_INT);
125 pev->SetMinValue(-1);
126 pev->SetMaxValue(2);
127 pev->SetStepValue(1);
128 pev->SetValue(1);
129 pos.x = 500.0f/640.0f;
130 pc = pw->CreateCheck(pos, ddim, 0, invertControl);
131 pc->SetState(STATE_SHADOW);
132 };
133 pos.y += 15.0f/480.0f;
134 CreateJoystickControls("X:", EVENT_INTERFACE_JOYSTICK_X, EVENT_INTERFACE_JOYSTICK_X_INVERT);
135 CreateJoystickControls("Y:", EVENT_INTERFACE_JOYSTICK_Y, EVENT_INTERFACE_JOYSTICK_Y_INVERT);
136 CreateJoystickControls("Z:", EVENT_INTERFACE_JOYSTICK_Z, EVENT_INTERFACE_JOYSTICK_Z_INVERT);
137 CreateJoystickControls("CamX:", EVENT_INTERFACE_JOYSTICK_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT);
138 CreateJoystickControls("CamY:", EVENT_INTERFACE_JOYSTICK_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT);
139 CreateJoystickControls("CamZ:", EVENT_INTERFACE_JOYSTICK_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT);
140
141 pos.y -= 25.0f/480.0f;
142 pos.x = 420.0f/640.0f;
143 pos.y -= 5.0f/480.0f;
144 pw->CreateLabel(pos, ddim, 0, EVENT_LABEL3, "Deadzone:");
145 pos.y += 5.0f/480.0f;
146 pos.x = 480.0f/640.0f;
147 ddim.x = dim.x*2.2f;
148 pev = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_JOYSTICK_DEADZONE);
149 pev->SetState(STATE_SHADOW);
150 pev->SetType(EVT_100);
151 pev->SetMinValue(0);
152 pev->SetMaxValue(1);
153 pev->SetStepValue(0.01);
154
155 ddim.x = dim.x*6;
156 ddim.y = dim.y*1;
157 pos.x = ox+sx*10;
158 pos.y = oy+sy*2;
159 pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_KDEF);
160 pb->SetState(STATE_SHADOW);
161
162 UpdateSetupButtons();
163 }
164
EventProcess(const Event & event)165 bool CScreenSetupControls::EventProcess(const Event &event)
166 {
167 if (!CScreenSetup::EventProcess(event)) return false;
168
169 switch( event.type )
170 {
171 case EVENT_INTERFACE_KSCROLL:
172 UpdateKey();
173 break;
174
175 case EVENT_INTERFACE_KDEF:
176 m_input->SetDefaultInputBindings();
177 UpdateKey();
178 break;
179
180 case EVENT_INTERFACE_JOYSTICK_X_INVERT:
181 case EVENT_INTERFACE_JOYSTICK_Y_INVERT:
182 case EVENT_INTERFACE_JOYSTICK_Z_INVERT:
183 case EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT:
184 case EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT:
185 case EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT:
186 ToggleJoystickInvert(event.type);
187 ChangeSetupButtons();
188 UpdateSetupButtons();
189 break;
190
191 case EVENT_INTERFACE_JOYSTICK:
192 case EVENT_INTERFACE_JOYSTICK_X:
193 case EVENT_INTERFACE_JOYSTICK_Y:
194 case EVENT_INTERFACE_JOYSTICK_Z:
195 case EVENT_INTERFACE_JOYSTICK_CAM_X:
196 case EVENT_INTERFACE_JOYSTICK_CAM_Y:
197 case EVENT_INTERFACE_JOYSTICK_CAM_Z:
198 case EVENT_INTERFACE_JOYSTICK_DEADZONE:
199 ChangeSetupButtons();
200 UpdateSetupButtons();
201 break;
202
203 default:
204 if (event.type >= EVENT_INTERFACE_KEY && event.type <= EVENT_INTERFACE_KEY_END)
205 {
206 ChangeKey(event.type);
207 UpdateKey();
208 break;
209 }
210 return true;
211 }
212 return false;
213 }
214
ChangeSetupButtons()215 void CScreenSetupControls::ChangeSetupButtons()
216 {
217 CWindow* pw;
218 CList* pli;
219 CEditValue* pev;
220 CCheck* pc;
221
222 pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
223 if ( pw == nullptr ) return;
224
225 pli = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_JOYSTICK));
226 if ( pli != nullptr )
227 {
228 if (pli->GetSelect() > 0)
229 {
230 m_app->SetJoystickEnabled(false);
231 m_app->ChangeJoystick(m_app->GetJoystickList().at(pli->GetSelect()-1));
232 m_app->SetJoystickEnabled(true);
233 }
234 else
235 {
236 m_app->SetJoystickEnabled(false);
237 }
238 }
239
240 auto HandleJoystickControls = [&](JoyAxisSlot joyAxis, EventType bindingControl, EventType invertControl)
241 {
242 if (nullptr != (pev = static_cast<CEditValue*>(pw->SearchControl(bindingControl))))
243 {
244 JoyAxisBinding binding = m_input->GetJoyAxisBinding(joyAxis);
245 binding.axis = static_cast<int>(round(pev->GetValue()));
246 m_input->SetJoyAxisBinding(joyAxis, binding);
247 }
248 if (nullptr != (pc = static_cast<CCheck*>(pw->SearchControl(invertControl))))
249 {
250 JoyAxisBinding binding = m_input->GetJoyAxisBinding(joyAxis);
251 binding.invert = pc->TestState(STATE_CHECK);
252 m_input->SetJoyAxisBinding(joyAxis, binding);
253 }
254 };
255 HandleJoystickControls(JOY_AXIS_SLOT_X, EVENT_INTERFACE_JOYSTICK_X, EVENT_INTERFACE_JOYSTICK_X_INVERT);
256 HandleJoystickControls(JOY_AXIS_SLOT_Y, EVENT_INTERFACE_JOYSTICK_Y, EVENT_INTERFACE_JOYSTICK_Y_INVERT);
257 HandleJoystickControls(JOY_AXIS_SLOT_Z, EVENT_INTERFACE_JOYSTICK_Z, EVENT_INTERFACE_JOYSTICK_Z_INVERT);
258 HandleJoystickControls(JOY_AXIS_SLOT_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT);
259 HandleJoystickControls(JOY_AXIS_SLOT_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT);
260 HandleJoystickControls(JOY_AXIS_SLOT_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT);
261
262 if (nullptr != (pev = static_cast<CEditValue*>(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_DEADZONE))))
263 {
264 m_input->SetJoystickDeadzone(pev->GetValue());
265 }
266 }
267
ToggleJoystickInvert(EventType type)268 void CScreenSetupControls::ToggleJoystickInvert(EventType type)
269 {
270 CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
271 if (pw == nullptr) return;
272
273 CCheck* pc = static_cast<CCheck*>(pw->SearchControl(type));
274 if (pc == nullptr) return;
275
276 pc->SetState(STATE_CHECK, !pc->TestState(STATE_CHECK));
277 }
278
279 // Updates the buttons during the setup phase.
280
UpdateSetupButtons()281 void CScreenSetupControls::UpdateSetupButtons()
282 {
283 CWindow* pw;
284 CList* pli;
285 CEditValue* pev;
286 CCheck* pc;
287
288 pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
289 if (pw == nullptr) return;
290
291 pli = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_JOYSTICK));
292 if (pli != nullptr)
293 {
294 pli->Flush();
295 pli->SetItemName(0, "[No joystick]");
296 auto joysticks = m_app->GetJoystickList();
297 for (unsigned int i = 0; i < joysticks.size(); i++)
298 {
299 pli->SetItemName(1 + i, joysticks[i].name);
300 }
301 pli->SetSelect(m_app->GetJoystickEnabled() ? m_app->GetJoystick().index + 1 : 0);
302 }
303
304 auto HandleJoystickControls = [&](JoyAxisSlot joyAxis, EventType bindingControl, EventType invertControl)
305 {
306 if (nullptr != (pev = static_cast<CEditValue*>(pw->SearchControl(bindingControl))))
307 {
308 pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled());
309 pev->SetMaxValue(m_app->GetJoystick().axisCount-1);
310 pev->SetValue(m_input->GetJoyAxisBinding(joyAxis).axis);
311 }
312 if (nullptr != (pc = static_cast<CCheck*>(pw->SearchControl(invertControl))))
313 {
314 pc->SetState(STATE_ENABLE, m_app->GetJoystickEnabled());
315 pc->SetState(STATE_CHECK, m_input->GetJoyAxisBinding(joyAxis).invert);
316 }
317 };
318 HandleJoystickControls(JOY_AXIS_SLOT_X, EVENT_INTERFACE_JOYSTICK_X, EVENT_INTERFACE_JOYSTICK_X_INVERT);
319 HandleJoystickControls(JOY_AXIS_SLOT_Y, EVENT_INTERFACE_JOYSTICK_Y, EVENT_INTERFACE_JOYSTICK_Y_INVERT);
320 HandleJoystickControls(JOY_AXIS_SLOT_Z, EVENT_INTERFACE_JOYSTICK_Z, EVENT_INTERFACE_JOYSTICK_Z_INVERT);
321 HandleJoystickControls(JOY_AXIS_SLOT_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X, EVENT_INTERFACE_JOYSTICK_CAM_X_INVERT);
322 HandleJoystickControls(JOY_AXIS_SLOT_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y, EVENT_INTERFACE_JOYSTICK_CAM_Y_INVERT);
323 HandleJoystickControls(JOY_AXIS_SLOT_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z, EVENT_INTERFACE_JOYSTICK_CAM_Z_INVERT);
324
325 if (nullptr != (pev = static_cast<CEditValue*>(pw->SearchControl(EVENT_INTERFACE_JOYSTICK_DEADZONE))))
326 {
327 pev->SetState(STATE_ENABLE, m_app->GetJoystickEnabled());
328 pev->SetValue(m_input->GetJoystickDeadzone());
329 }
330 }
331
332 // Updates the list of keys.
333
UpdateKey()334 void CScreenSetupControls::UpdateKey()
335 {
336 CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
337 if (pw == nullptr) return;
338
339 CScroll* ps = static_cast<CScroll*>(pw->SearchControl(EVENT_INTERFACE_KSCROLL));
340 if (ps == nullptr) return;
341
342 int first = static_cast<int>(ps->GetVisibleValue()*(INPUT_SLOT_MAX-KEY_VISIBLE));
343
344 for (int i = 0; i < INPUT_SLOT_MAX; i++)
345 pw->DeleteControl(static_cast<EventType>(EVENT_INTERFACE_KEY+i));
346
347 Math::Point dim;
348 dim.x = 250.0f/640.0f;
349 dim.y = 20.0f/480.0f;
350 Math::Point pos;
351 pos.x = 110.0f/640.0f;
352 pos.y = 128.0f/480.0f + dim.y*(KEY_VISIBLE-1);
353 for (int i = 0; i < KEY_VISIBLE; i++)
354 {
355 pw->CreateKey(pos, dim, -1, static_cast<EventType>(EVENT_INTERFACE_KEY+first+i));
356 CKey* pk = static_cast<CKey*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_KEY+first+i)));
357 if (pk == nullptr) break;
358
359 pk->SetBinding(m_input->GetInputBinding(static_cast<InputSlot>(first+i)));
360 pos.y -= dim.y;
361 }
362 }
363
364 // Change a key.
365
ChangeKey(EventType event)366 void CScreenSetupControls::ChangeKey(EventType event)
367 {
368 CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
369 if (pw == nullptr) return;
370
371 CScroll* ps = static_cast<CScroll*>(pw->SearchControl(EVENT_INTERFACE_KSCROLL));
372 if (ps == nullptr) return;
373
374 for (int i = 0; i < INPUT_SLOT_MAX; i++)
375 {
376 if ( EVENT_INTERFACE_KEY+i == event )
377 {
378 CKey* pk = static_cast<CKey*>(pw->SearchControl(static_cast<EventType>(EVENT_INTERFACE_KEY+i)));
379 if (pk == nullptr) break;
380
381 m_input->SetInputBinding(static_cast<InputSlot>(i), pk->GetBinding());
382 }
383 }
384 }
385
386 } // namespace Ui
387