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 
21 #include "ui/controls/editvalue.h"
22 
23 #include "common/event.h"
24 #include "common/make_unique.h"
25 
26 #include "level/robotmain.h"
27 
28 #include "ui/controls/button.h"
29 #include "ui/controls/edit.h"
30 #include "ui/controls/interface.h"
31 
32 #include <cstdio>
33 
34 
35 
36 namespace Ui
37 {
38 // Object's constructor.
39 
CEditValue()40 CEditValue::CEditValue() : CControl ()
41 {
42     m_type = EVT_100;  // %
43     m_stepValue = 0.1f;  // 10%
44     m_minValue = 0.0f;  // 0%
45     m_maxValue = 1.0f;  // 100%
46 
47     m_interface = CRobotMain::GetInstancePointer()->GetInterface();
48 }
49 
50 // Object's destructor.
51 
~CEditValue()52 CEditValue::~CEditValue()
53 {
54 }
55 
56 
57 // Creates a new button.
58 
Create(Math::Point pos,Math::Point dim,int icon,EventType eventType)59 bool CEditValue::Create(Math::Point pos, Math::Point dim, int icon, EventType eventType)
60 {
61     if ( eventType == EVENT_NULL )  eventType = GetUniqueEventType();
62     CControl::Create(pos, dim, icon, eventType);
63 
64     GlintDelete();
65 
66     m_edit = MakeUnique<Ui::CEdit>();
67     m_edit->Create(pos, dim, 0, EVENT_NULL);
68     m_edit->SetMaxChar(4);
69 
70     m_buttonUp = MakeUnique<Ui::CButton>();
71     m_buttonUp->Create(pos, dim, 49, EVENT_NULL);  // ^
72     m_buttonUp->SetRepeat(true);
73 
74     m_buttonDown = MakeUnique<Ui::CButton>();
75     m_buttonDown->Create(pos, dim, 50, EVENT_NULL);  // v
76     m_buttonDown->SetRepeat(true);
77 
78     MoveAdjust();
79     return true;
80 }
81 
82 
SetPos(Math::Point pos)83 void CEditValue::SetPos(Math::Point pos)
84 {
85     CControl::SetPos(pos);
86     MoveAdjust();
87 }
88 
SetDim(Math::Point dim)89 void CEditValue::SetDim(Math::Point dim)
90 {
91     CControl::SetDim(dim);
92     MoveAdjust();
93 }
94 
MoveAdjust()95 void CEditValue::MoveAdjust()
96 {
97     Math::Point     pos, dim;
98 
99     if (m_edit != nullptr)
100     {
101         pos.x = m_pos.x;
102         pos.y = m_pos.y;
103         dim.x = m_dim.x-m_dim.y*0.6f;
104         dim.y = m_dim.y;
105         m_edit->SetPos(pos);
106         m_edit->SetDim(dim);
107     }
108 
109     if (m_buttonUp != nullptr)
110     {
111         pos.x = m_pos.x+m_dim.x-m_dim.y*0.6f;
112         pos.y = m_pos.y+m_dim.y*0.5f;
113         dim.x = m_dim.y*0.6f;
114         dim.y = m_dim.y*0.5f;
115         m_buttonUp->SetPos(pos);
116         m_buttonUp->SetDim(dim);
117     }
118 
119     if (m_buttonDown != nullptr)
120     {
121         pos.x = m_pos.x+m_dim.x-m_dim.y*0.6f;
122         pos.y = m_pos.y;
123         dim.x = m_dim.y*0.6f;
124         dim.y = m_dim.y*0.5f;
125         m_buttonDown->SetPos(pos);
126         m_buttonDown->SetDim(dim);
127     }
128 }
129 
130 
131 // Management of an event.
132 
EventProcess(const Event & event)133 bool CEditValue::EventProcess(const Event &event)
134 {
135     CControl::EventProcess(event);
136 
137     if ( (m_state & STATE_VISIBLE) == 0 )  return true;
138     if ( (m_state & STATE_ENABLE) == 0 )  return true;
139     if ( m_state & STATE_DEAD )  return true;
140 
141     if (m_edit != nullptr)
142     {
143         if ( m_edit->GetFocus()           &&
144              event.type == EVENT_KEY_DOWN &&
145              event.GetData<KeyEventData>()->key == KEY(RETURN)     )
146         {
147             float value = GetValue();
148             if ( value > m_maxValue )  value = m_maxValue;
149             if ( value < m_minValue )  value = m_minValue;
150             SetValue(value, true);
151             HiliteValue(event);
152         }
153         if ( !m_edit->EventProcess(event) )  return false;
154 
155         if ( event.type == m_edit->GetEventType() )
156         {
157             m_event->AddEvent(Event(m_eventType));
158         }
159     }
160 
161     if (m_buttonUp != nullptr)
162     {
163         if ( event.type == m_buttonUp->GetEventType() )
164         {
165             float value = GetValue()+m_stepValue;
166             if ( value > m_maxValue )  value = m_maxValue;
167             SetValue(value, true);
168             HiliteValue(event);
169         }
170         if ( !m_buttonUp->EventProcess(event) )  return false;
171     }
172 
173     if (m_buttonDown != nullptr)
174     {
175         if ( event.type == m_buttonDown->GetEventType() )
176         {
177             float value = GetValue()-m_stepValue;
178             if ( value < m_minValue )  value = m_minValue;
179             SetValue(value, true);
180             HiliteValue(event);
181         }
182         if ( !m_buttonDown->EventProcess(event) )  return false;
183     }
184 
185     if (event.type == EVENT_MOUSE_WHEEL &&
186         Detect(event.mousePos))
187     {
188         float value = GetValue() + (m_stepValue * event.GetData<MouseWheelEventData>()->y);
189         if ( value < m_minValue )  value = m_minValue;
190         if ( value > m_maxValue )  value = m_maxValue;
191         SetValue(value, true);
192         HiliteValue(event);
193         return false;
194     }
195 
196     return true;
197 }
198 
199 
200 // Puts in evidence the edited value.
201 
HiliteValue(const Event & event)202 void CEditValue::HiliteValue(const Event &event)
203 {
204     if (m_edit == nullptr)  return;
205 
206     int pos = m_edit->GetTextLength();
207     if ( m_type == EVT_100 && pos > 0 )
208     {
209         pos --;  // not only selects the "%"
210     }
211 
212     m_edit->SetCursor(pos, 0);
213     m_interface->SetFocus(m_edit.get());
214 
215     Event newEvent = event.Clone();
216     newEvent.type = EVENT_FOCUS;
217     newEvent.customParam = m_edit->GetEventType();
218     m_event->AddEvent(std::move(newEvent));  // defocus the other objects
219 }
220 
221 
222 // Draw button.
223 
Draw()224 void CEditValue::Draw()
225 {
226     if ( (m_state & STATE_VISIBLE) == 0 )  return;
227 
228     if ( m_state & STATE_SHADOW )
229     {
230         DrawShadow(m_pos, m_dim);
231     }
232 
233     if (m_edit != nullptr)
234     {
235         m_edit->SetState(STATE_ENABLE, TestState(STATE_ENABLE));
236         m_edit->Draw();
237     }
238     if (m_buttonUp != nullptr)
239     {
240         m_buttonUp->SetState(STATE_DEAD, TestState(STATE_DEAD));
241         m_buttonUp->Draw();
242     }
243     if (m_buttonDown != nullptr)
244     {
245         m_buttonDown->SetState(STATE_DEAD, TestState(STATE_DEAD));
246         m_buttonDown->Draw();
247     }
248 }
249 
250 
251 // Choosing the type of value.
252 
SetType(EditValueType type)253 void CEditValue::SetType(EditValueType type)
254 {
255     m_type = type;
256 }
257 
GetType()258 EditValueType CEditValue::GetType()
259 {
260     return m_type;
261 }
262 
263 
264 // Changes the value.
265 
SetValue(float value,bool bSendMessage)266 void CEditValue::SetValue(float value, bool bSendMessage)
267 {
268     char    text[100];
269 
270     if ( m_edit == nullptr )  return;
271 
272     text[0] = 0;
273 
274     if ( m_type == EVT_INT )
275     {
276         sprintf(text, "%d", static_cast<int>(value));
277     }
278 
279     if ( m_type == EVT_FLOAT )
280     {
281         sprintf(text, "%.2f", value);
282     }
283 
284     if ( m_type == EVT_100 )
285     {
286         sprintf(text, "%d%%", static_cast<int>(value*100.0f));
287     }
288 
289     m_edit->SetText(text);
290 
291     if ( bSendMessage )
292     {
293         m_event->AddEvent(Event(m_eventType));
294     }
295 }
296 
297 // Return the edited value.
298 
GetValue()299 float CEditValue::GetValue()
300 {
301     std::string text;
302     float   value = 0.0f;
303 
304     if ( m_edit != nullptr )
305     {
306         text = m_edit->GetText(100);
307         sscanf(text.c_str(), "%f", &value);
308 
309         if ( m_type == EVT_100 )
310         {
311             value = (value+0.5f)/100.0f;
312             if ( value < 0.01f )  value = 0.0f;  // less than 1%?
313         }
314     }
315     return value;
316 }
317 
318 
319 // Management not for buttons.
320 
SetStepValue(float value)321 void CEditValue::SetStepValue(float value)
322 {
323     m_stepValue = value;
324 }
325 
GetStepValue()326 float CEditValue::GetStepValue()
327 {
328     return m_stepValue;
329 }
330 
331 
332 // Management of the minimum value.
333 
SetMinValue(float value)334 void CEditValue::SetMinValue(float value)
335 {
336     m_minValue = value;
337 }
338 
GetMinValue()339 float CEditValue::GetMinValue()
340 {
341     return m_minValue;
342 }
343 
344 
345 // Management of the maximum value.
346 
SetMaxValue(float value)347 void CEditValue::SetMaxValue(float value)
348 {
349     m_maxValue = value;
350 }
351 
GetMaxValue()352 float CEditValue::GetMaxValue()
353 {
354     return m_maxValue;
355 }
356 
SetInterface(CInterface * interface)357 void CEditValue::SetInterface(CInterface* interface)
358 {
359     m_interface = interface;
360 }
361 
362 }
363