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/controls/window.h"
21
22 #include "ui/controls/button.h"
23 #include "ui/controls/check.h"
24 #include "ui/controls/color.h"
25 #include "ui/controls/control.h"
26 #include "ui/controls/edit.h"
27 #include "ui/controls/editvalue.h"
28 #include "ui/controls/enumslider.h"
29 #include "ui/controls/gauge.h"
30 #include "ui/controls/group.h"
31 #include "ui/controls/image.h"
32 #include "ui/controls/key.h"
33 #include "ui/controls/label.h"
34 #include "ui/controls/list.h"
35 #include "ui/controls/map.h"
36 #include "ui/controls/scroll.h"
37 #include "ui/controls/shortcut.h"
38 #include "ui/controls/slider.h"
39 #include "ui/controls/target.h"
40
41 #include <algorithm>
42
43
44 namespace Ui
45 {
46 // Object's constructor.
47
CWindow()48 CWindow::CWindow() : CControl()
49 {
50 m_bTrashEvent = true;
51 m_bMaximized = false;
52 m_bMinimized = false;
53 m_bFixed = false;
54
55 m_minDim = Math::Point(0.0f, 0.0f);
56 m_maxDim = Math::Point(1.0f, 1.0f);
57
58 m_bMovable = false;
59 m_bRedim = false;
60 m_bClosable = false;
61 m_bCapture = false;
62 m_pressFlags = 0;
63 m_pressMouse = Gfx::ENG_MOUSE_NORM;
64
65 // m_fontStretch = NORMSTRETCH*1.2f;
66 }
67
68 // Object's destructor.
69
~CWindow()70 CWindow::~CWindow()
71 {
72 }
73
74
75 // Purge all the controls.
76
Flush()77 void CWindow::Flush()
78 {
79 m_controls.clear();
80
81 m_buttonReduce.reset();
82 m_buttonFull.reset();
83 m_buttonClose.reset();
84 }
85
86
87 // Creates a new window.
88
Create(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)89 bool CWindow::Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
90 {
91 if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventType();
92
93 CControl::Create(pos, dim, icon, eventMsg);
94 return true;
95 }
96
97 template<typename ControlClass>
CreateControl(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)98 ControlClass* CWindow::CreateControl(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
99 {
100 auto control = MakeUnique<ControlClass>();
101 control->Create(pos, dim, icon, eventMsg);
102 auto* controlPtr = control.get();
103 m_controls.push_back(std::move(control));
104 return controlPtr;
105 }
106
107
108 // Creates a new button.
109
CreateButton(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)110 CButton* CWindow::CreateButton(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
111 {
112 return CreateControl<CButton>(pos, dim, icon, eventMsg);
113 }
114
115 // Creates a new button.
116
CreateColor(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)117 CColor* CWindow::CreateColor(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
118 {
119 return CreateControl<CColor>(pos, dim, icon, eventMsg);
120 }
121
122 // Creates a new button.
123
CreateCheck(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)124 CCheck* CWindow::CreateCheck(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
125 {
126 return CreateControl<CCheck>(pos, dim, icon, eventMsg);
127 }
128
129 // Creates a new button.
130
CreateKey(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)131 CKey* CWindow::CreateKey(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
132 {
133 return CreateControl<CKey>(pos, dim, icon, eventMsg);
134 }
135
136 // Creates a new button.
137
CreateGroup(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)138 CGroup* CWindow::CreateGroup(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
139 {
140 return CreateControl<CGroup>(pos, dim, icon, eventMsg);
141 }
142
143 // Creates a new button.
144
CreateImage(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)145 CImage* CWindow::CreateImage(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
146 {
147 return CreateControl<CImage>(pos, dim, icon, eventMsg);
148 }
149
150 // Creates a new label.
151
CreateLabel(Math::Point pos,Math::Point dim,int icon,EventType eventMsg,std::string name)152 CLabel* CWindow::CreateLabel(Math::Point pos, Math::Point dim, int icon, EventType eventMsg, std::string name)
153 {
154 CLabel* label = CreateControl<CLabel>(pos, dim, icon, eventMsg);
155
156 auto p = name.find("\\");
157 if (p == std::string::npos)
158 label->SetName(name);
159 else
160 label->SetName(name.substr(0, p));
161
162 return label;
163 }
164
165 // Creates a new editable pave.
166
CreateEdit(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)167 CEdit* CWindow::CreateEdit(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
168 {
169 return CreateControl<CEdit>(pos, dim, icon, eventMsg);
170 }
171
172 // Creates a new editable pave.
173
CreateEditValue(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)174 CEditValue* CWindow::CreateEditValue(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
175 {
176 return CreateControl<CEditValue>(pos, dim, icon, eventMsg);
177 }
178
179 // Creates a new elevator.
180
CreateScroll(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)181 CScroll* CWindow::CreateScroll(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
182 {
183 if (eventMsg == EVENT_NULL)
184 eventMsg = GetUniqueEventType();
185
186 return CreateControl<CScroll>(pos, dim, icon, eventMsg);
187 }
188
189 // Creates a new cursor.
190
CreateSlider(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)191 CSlider* CWindow::CreateSlider(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
192 {
193 if (eventMsg == EVENT_NULL)
194 eventMsg = GetUniqueEventType();
195
196 return CreateControl<CSlider>(pos, dim, icon, eventMsg);
197 }
198
CreateEnumSlider(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)199 CEnumSlider* CWindow::CreateEnumSlider(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
200 {
201 if (eventMsg == EVENT_NULL)
202 eventMsg = GetUniqueEventType();
203
204 return CreateControl<CEnumSlider>(pos, dim, icon, eventMsg);
205 }
206
207 // Creates a new list.
208 // if expand is less then zero, then the list would try to use expand's absolute value,
209 // and try to scale items to some size, so that dim of the list would not change after
210 // adjusting
211
CreateList(Math::Point pos,Math::Point dim,int icon,EventType eventMsg,float expand)212 CList* CWindow::CreateList(Math::Point pos, Math::Point dim, int icon, EventType eventMsg, float expand)
213 {
214 if (eventMsg == EVENT_NULL)
215 eventMsg = GetUniqueEventType();
216
217 auto list = MakeUnique<CList>();
218 list->Create(pos, dim, icon, eventMsg, expand);
219 auto* listPtr = list.get();
220 m_controls.push_back(std::move(list));
221 return listPtr;
222 }
223
224 // Creates a new shortcut.
225
CreateShortcut(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)226 CShortcut* CWindow::CreateShortcut(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
227 {
228 if (eventMsg == EVENT_NULL)
229 eventMsg = GetUniqueEventType();
230
231 return CreateControl<CShortcut>(pos, dim, icon, eventMsg);
232 }
233
234 // Creates a new card.
235
CreateMap(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)236 CMap* CWindow::CreateMap(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
237 {
238 if (eventMsg == EVENT_NULL)
239 eventMsg = GetUniqueEventType();
240
241 return CreateControl<CMap>(pos, dim, icon, eventMsg);
242 }
243
244 // Creates a new gauge.
245
CreateGauge(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)246 CGauge* CWindow::CreateGauge(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
247 {
248 if (eventMsg == EVENT_NULL)
249 eventMsg = GetUniqueEventType();
250
251 return CreateControl<CGauge>(pos, dim, icon, eventMsg);
252 }
253
254 // Creates a new target.
255
CreateTarget(Math::Point pos,Math::Point dim,int icon,EventType eventMsg)256 CTarget* CWindow::CreateTarget(Math::Point pos, Math::Point dim, int icon, EventType eventMsg)
257 {
258 if (eventMsg == EVENT_NULL)
259 eventMsg = GetUniqueEventType();
260
261 return CreateControl<CTarget>(pos, dim, icon, eventMsg);
262 }
263
264 // Removes a control.
265
DeleteControl(EventType eventMsg)266 bool CWindow::DeleteControl(EventType eventMsg)
267 {
268 auto controlIt = std::find_if(m_controls.begin(), m_controls.end(),
269 [eventMsg](const std::unique_ptr<CControl>& control)
270 {
271 return control->GetEventType() == eventMsg;
272 });
273
274 if (controlIt == m_controls.end())
275 return false;
276
277 m_controls.erase(controlIt);
278 return true;
279 }
280
281 // Gives a control.
282
SearchControl(EventType eventMsg)283 CControl* CWindow::SearchControl(EventType eventMsg)
284 {
285 auto controlIt = std::find_if(m_controls.begin(), m_controls.end(),
286 [eventMsg](const std::unique_ptr<CControl>& control)
287 {
288 return control->GetEventType() == eventMsg;
289 });
290
291 if (controlIt == m_controls.end())
292 return nullptr;
293
294 return controlIt->get();
295 }
296
297
298 // Makes the tooltip binds to the window.
299
GetTooltip(Math::Point pos,std::string & name)300 bool CWindow::GetTooltip(Math::Point pos, std::string &name)
301 {
302 for (auto& control : m_controls)
303 {
304 if (control->GetTooltip(pos, name))
305 return true;
306 }
307
308 if (m_buttonClose != nullptr &&
309 m_buttonClose->GetTooltip(pos, name))
310 {
311 return true;
312 }
313 if (m_buttonFull != nullptr &&
314 m_buttonFull->GetTooltip(pos, name))
315 {
316 return true;
317 }
318 if (m_buttonReduce != nullptr &&
319 m_buttonReduce->GetTooltip(pos, name))
320 {
321 return true;
322 }
323
324 if ( Detect(pos) ) // in the window?
325 {
326 name = m_tooltip;
327 return true;
328 }
329
330 return false;
331 }
332
333
334 // Specifies the name for the title bar.
335
SetName(std::string name,bool tooltip)336 void CWindow::SetName(std::string name, bool tooltip)
337 {
338 CControl::SetName(name, tooltip);
339
340 m_buttonReduce.reset();
341 m_buttonFull.reset();
342 m_buttonClose.reset();
343
344 bool bAdjust = false;
345
346 if ( m_name.length() > 0 && m_bRedim ) // title bar exists?
347 {
348 m_buttonReduce = MakeUnique<CButton>();
349 m_buttonReduce->Create(m_pos, m_dim, 0, EVENT_NULL);
350
351 m_buttonFull = MakeUnique<CButton>();
352 m_buttonFull->Create(m_pos, m_dim, 0, EVENT_NULL);
353
354 bAdjust = true;
355 }
356
357 if ( m_name.length() > 0 && m_bClosable ) // title bar exists?
358 {
359 m_buttonClose = MakeUnique<CButton>();
360 m_buttonClose->Create(m_pos, m_dim, 0, EVENT_NULL);
361
362 bAdjust = true;
363 }
364
365 if ( bAdjust )
366 {
367 AdjustButtons();
368 }
369
370 MoveAdjust();
371 }
372
373
SetPos(Math::Point pos)374 void CWindow::SetPos(Math::Point pos)
375 {
376 CControl::SetPos(pos);
377 MoveAdjust();
378 }
379
SetDim(Math::Point dim)380 void CWindow::SetDim(Math::Point dim)
381 {
382 if ( dim.x < m_minDim.x ) dim.x = m_minDim.x;
383 if ( dim.x > m_maxDim.x ) dim.x = m_maxDim.x;
384 if ( dim.y < m_minDim.y ) dim.y = m_minDim.y;
385 if ( dim.y > m_maxDim.y ) dim.y = m_maxDim.y;
386
387 CControl::SetDim(dim);
388 MoveAdjust();
389 }
390
MoveAdjust()391 void CWindow::MoveAdjust()
392 {
393 float h = m_engine->GetText()->GetHeight(m_fontType, m_fontSize);
394 Math::Point dim;
395 dim.y = h*1.2f;
396 dim.x = dim.y*0.75f;
397
398 float offset = 0.0f;
399 if (m_buttonClose != nullptr)
400 {
401 Math::Point pos;
402 pos.x = m_pos.x+m_dim.x-0.01f-dim.x;
403 pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
404 m_buttonClose->SetPos(pos);
405 m_buttonClose->SetDim(dim);
406 offset = dim.x*1.0f;
407 }
408 else
409 {
410 offset = 0.0f;
411 }
412
413 if (m_buttonFull != nullptr)
414 {
415 Math::Point pos;
416 pos.x = m_pos.x+m_dim.x-0.01f-dim.x-offset;
417 pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
418 m_buttonFull->SetPos(pos);
419 m_buttonFull->SetDim(dim);
420 }
421
422 if (m_buttonReduce != nullptr)
423 {
424 Math::Point pos;
425 pos.x = m_pos.x+m_dim.x-0.01f-dim.x*2.0f-offset;
426 pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
427 m_buttonReduce->SetPos(pos);
428 m_buttonReduce->SetDim(dim);
429 }
430 }
431
432
SetMinDim(Math::Point dim)433 void CWindow::SetMinDim(Math::Point dim)
434 {
435 m_minDim = dim;
436 }
437
SetMaxDim(Math::Point dim)438 void CWindow::SetMaxDim(Math::Point dim)
439 {
440 m_maxDim = dim;
441 }
442
GetMinDim()443 Math::Point CWindow::GetMinDim()
444 {
445 return m_minDim;
446 }
447
GetMaxDim()448 Math::Point CWindow::GetMaxDim()
449 {
450 return m_maxDim;
451 }
452
453
454 // Indicates whether the window is moved.
455
SetMovable(bool bMode)456 void CWindow::SetMovable(bool bMode)
457 {
458 m_bMovable = bMode;
459 }
460
GetMovable()461 bool CWindow::GetMovable()
462 {
463 return m_bMovable;
464 }
465
466
467 // Management of the presence of minimize/maximize buttons.
468
SetRedim(bool bMode)469 void CWindow::SetRedim(bool bMode)
470 {
471 m_bRedim = bMode;
472 }
473
GetRedim()474 bool CWindow::GetRedim()
475 {
476 return m_bRedim;
477 }
478
479
480 // Management of the presence of the close button.
481
SetClosable(bool bMode)482 void CWindow::SetClosable(bool bMode)
483 {
484 m_bClosable = bMode;
485 }
486
GetClosable()487 bool CWindow::GetClosable()
488 {
489 return m_bClosable;
490 }
491
492
SetMaximized(bool bMaxi)493 void CWindow::SetMaximized(bool bMaxi)
494 {
495 m_bMaximized = bMaxi;
496 AdjustButtons();
497 }
498
GetMaximized()499 bool CWindow::GetMaximized()
500 {
501 return m_bMaximized;
502 }
503
SetMinimized(bool bMini)504 void CWindow::SetMinimized(bool bMini)
505 {
506 m_bMinimized = bMini;
507 AdjustButtons();
508 }
509
GetMinimized()510 bool CWindow::GetMinimized()
511 {
512 return m_bMinimized;
513 }
514
SetFixed(bool bFix)515 void CWindow::SetFixed(bool bFix)
516 {
517 m_bFixed = bFix;
518 }
519
GetFixed()520 bool CWindow::GetFixed()
521 {
522 return m_bFixed;
523 }
524
525
526 // Adjusts the buttons in the title bar.
527
AdjustButtons()528 void CWindow::AdjustButtons()
529 {
530 std::string res;
531
532 if (m_buttonFull != nullptr)
533 {
534 if ( m_bMaximized )
535 {
536 m_buttonFull->SetIcon(54);
537 GetResource(RES_TEXT, RT_WINDOW_STANDARD, res);
538 m_buttonFull->SetTooltip(res);
539 }
540 else
541 {
542 m_buttonFull->SetIcon(52);
543 GetResource(RES_TEXT, RT_WINDOW_MAXIMIZED, res);
544 m_buttonFull->SetTooltip(res);
545 }
546 }
547
548 if (m_buttonReduce != nullptr)
549 {
550 if ( m_bMinimized )
551 {
552 m_buttonReduce->SetIcon(54);
553 GetResource(RES_TEXT, RT_WINDOW_STANDARD, res);
554 m_buttonReduce->SetTooltip(res);
555 }
556 else
557 {
558 m_buttonReduce->SetIcon(51);
559 GetResource(RES_TEXT, RT_WINDOW_MINIMIZED, res);
560 m_buttonReduce->SetTooltip(res);
561 }
562 }
563
564 if (m_buttonClose != nullptr)
565 {
566 m_buttonClose->SetIcon(11); // x
567 GetResource(RES_TEXT, RT_WINDOW_CLOSE, res);
568 m_buttonClose->SetTooltip(res);
569 }
570 }
571
572
SetTrashEvent(bool bTrash)573 void CWindow::SetTrashEvent(bool bTrash)
574 {
575 m_bTrashEvent = bTrash;
576 }
577
GetTrashEvent()578 bool CWindow::GetTrashEvent()
579 {
580 return m_bTrashEvent;
581 }
582
583
584 // Returns the message from the button "reduce".
585
GetEventTypeReduce()586 EventType CWindow::GetEventTypeReduce()
587 {
588 if (m_buttonReduce == nullptr) return EVENT_NULL;
589 return m_buttonReduce->GetEventType();
590 }
591
592 // Returns the message from the button "full".
593
GetEventTypeFull()594 EventType CWindow::GetEventTypeFull()
595 {
596 if (m_buttonFull == nullptr) return EVENT_NULL;
597 return m_buttonFull->GetEventType();
598 }
599
600 // Returns the message from the button "close".
601
GetEventTypeClose()602 EventType CWindow::GetEventTypeClose()
603 {
604 if (m_buttonClose == nullptr) return EVENT_NULL;
605 return m_buttonClose->GetEventType();
606 }
607
608
609 // Detects whether the mouse is in an edge of the window, to resize it.
610 // Bit returns: 0 = left, 1 = down, 2 = right, 3 = up, 1 = all.
611
BorderDetect(Math::Point pos)612 int CWindow::BorderDetect(Math::Point pos)
613 {
614 Math::Point dim;
615 float h;
616 int flags;
617
618 if ( m_bMaximized || m_bMinimized || m_bFixed ) return 0;
619
620 flags = 0;
621 if ( pos.x < m_pos.x+0.030f )
622 {
623 flags |= (1<<0);
624 }
625 if ( pos.y < m_pos.y+0.020f )
626 {
627 flags |= (1<<1);
628 }
629 if ( pos.x > m_pos.x+m_dim.x-0.030f )
630 {
631 flags |= (1<<2);
632 }
633 if ( pos.y > m_pos.y+m_dim.y-0.020f )
634 {
635 flags |= (1<<3);
636 }
637
638 if ( pos.x > m_pos.x+ 0.015f &&
639 pos.x < m_pos.x+m_dim.x-0.015f &&
640 pos.y > m_pos.y+ 0.010f &&
641 pos.y < m_pos.y+m_dim.y-0.010f )
642 {
643 flags = 0;
644 }
645
646 if ( flags == 0 )
647 {
648 h = m_engine->GetText()->GetHeight(m_fontType, m_fontSize);
649 dim.y = h*1.2f;
650 dim.x = dim.y*0.75f;
651 if ( pos.x < m_pos.x+m_dim.x-0.01f-dim.x*3.0f &&
652 pos.y >= m_pos.y+m_dim.y-0.01f-h*1.2f )
653 {
654 flags = -1;
655 }
656 }
657
658 return flags;
659 }
660
661 // Management of an event.
662
EventProcess(const Event & event)663 bool CWindow::EventProcess(const Event &event)
664 {
665 if ( event.type == EVENT_MOUSE_MOVE || event.type == EVENT_MOUSE_BUTTON_DOWN || event.type == EVENT_MOUSE_BUTTON_UP )
666 {
667 if ( m_bCapture )
668 {
669 m_engine->SetMouseType(m_pressMouse);
670 }
671 else
672 {
673 m_pressMouse = Gfx::ENG_MOUSE_NORM;
674
675 if ( m_name.length() > 0 && m_bMovable && // title bar?
676 Detect(event.mousePos) )
677 {
678 int flags = BorderDetect(event.mousePos);
679 if ( flags == -1 )
680 {
681 m_pressMouse = Gfx::ENG_MOUSE_MOVE; // +
682 }
683 else if ( ((flags & (1<<0)) && (flags & (1<<3))) ||
684 ((flags & (1<<1)) && (flags & (1<<2))) )
685 {
686 m_pressMouse = Gfx::ENG_MOUSE_MOVEI; // \ //
687 }
688 else if ( ((flags & (1<<0)) && (flags & (1<<1))) ||
689 ((flags & (1<<2)) && (flags & (1<<3))) )
690 {
691 m_pressMouse = Gfx::ENG_MOUSE_MOVED; // /
692 }
693 else if ( (flags & (1<<0)) || (flags & (1<<2)) )
694 {
695 m_pressMouse = Gfx::ENG_MOUSE_MOVEH; // -
696 }
697 else if ( (flags & (1<<1)) || (flags & (1<<3)) )
698 {
699 m_pressMouse = Gfx::ENG_MOUSE_MOVEV; // |
700 }
701 }
702
703 if ( m_pressMouse != Gfx::ENG_MOUSE_NORM )
704 {
705 m_engine->SetMouseType(m_pressMouse);
706 }
707 }
708 }
709
710 if ( !m_bCapture )
711 {
712 for (auto& control : m_controls)
713 {
714 if (! control->EventProcess(event))
715 return false;
716 }
717
718 if (m_buttonReduce != nullptr)
719 {
720 m_buttonReduce->EventProcess(event);
721 }
722 if (m_buttonFull != nullptr)
723 {
724 m_buttonFull->EventProcess(event);
725 }
726 if (m_buttonClose != nullptr)
727 {
728 m_buttonClose->EventProcess(event);
729 }
730 }
731
732 if (m_bTrashEvent &&
733 event.type == EVENT_MOUSE_BUTTON_DOWN &&
734 event.GetData<MouseButtonEventData>()->button == MOUSE_BUTTON_LEFT)
735 {
736 if ( Detect(event.mousePos) )
737 {
738 if ( m_name.length() > 0 && m_bMovable ) // title bar?
739 {
740 m_pressFlags = BorderDetect(event.mousePos);
741 if ( m_pressFlags != 0 )
742 {
743 m_bCapture = true;
744 m_pressPos = event.mousePos;
745 }
746 }
747 return false;
748 }
749 }
750
751 if ( event.type == EVENT_MOUSE_MOVE && m_bCapture )
752 {
753 Math::Point pos = event.mousePos;
754 if ( m_pressFlags == -1 ) // all moves?
755 {
756 m_pos.x += pos.x-m_pressPos.x;
757 m_pos.y += pos.y-m_pressPos.y;
758 }
759 else
760 {
761 if ( m_pressFlags & (1<<0) ) // left edge?
762 {
763 if ( pos.x > m_pressPos.x+m_dim.x-m_minDim.x )
764 {
765 pos.x = m_pressPos.x+m_dim.x-m_minDim.x;
766 }
767 m_pos.x += pos.x-m_pressPos.x;
768 m_dim.x -= pos.x-m_pressPos.x;
769 }
770 if ( m_pressFlags & (1<<1) ) // bottom edge?
771 {
772 if ( pos.y > m_pressPos.y+m_dim.y-m_minDim.y )
773 {
774 pos.y = m_pressPos.y+m_dim.y-m_minDim.y;
775 }
776 m_pos.y += pos.y-m_pressPos.y;
777 m_dim.y -= pos.y-m_pressPos.y;
778 }
779 if ( m_pressFlags & (1<<2) ) // right edge?
780 {
781 if ( pos.x < m_pressPos.x-m_dim.x+m_minDim.x )
782 {
783 pos.x = m_pressPos.x-m_dim.x+m_minDim.x;
784 }
785 m_dim.x += pos.x-m_pressPos.x;
786 }
787 if ( m_pressFlags & (1<<3) ) // top edge?
788 {
789 if ( pos.y < m_pressPos.y-m_dim.y+m_minDim.y )
790 {
791 pos.y = m_pressPos.y-m_dim.y+m_minDim.y;
792 }
793 m_dim.y += pos.y-m_pressPos.y;
794 }
795 }
796 m_pressPos = pos;
797 AdjustButtons();
798
799 m_event->AddEvent(Event(m_eventType));
800 }
801
802 if (event.type == EVENT_MOUSE_BUTTON_UP &&
803 event.GetData<MouseButtonEventData>()->button == MOUSE_BUTTON_LEFT &&
804 m_bCapture)
805 {
806 m_bCapture = false;
807 }
808
809 return true;
810 }
811
812
813 // Draws the window.
814
Draw()815 void CWindow::Draw()
816 {
817 if ( (m_state & STATE_VISIBLE) == 0 ) return;
818
819 if ( m_state & STATE_SHADOW )
820 {
821 DrawShadow(m_pos, m_dim);
822 }
823
824 DrawVertex(m_pos, m_dim, m_icon); // draws the background
825
826 if ( m_name.length() > 0 ) // title bar?
827 {
828 float h = m_engine->GetText()->GetHeight(m_fontType, m_fontSize);
829
830 Math::Point pos, dim;
831 // Draws the shadow under the title bar.
832 {
833 Math::Point sPos, sDim;
834
835 pos.x = m_pos.x+0.01f;
836 dim.x = m_dim.x-0.02f;
837 pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
838 dim.y = h*1.2f;
839 DrawShadow(pos, dim);
840 }
841
842 float width = m_dim.x;
843 if ( m_bRedim ) width -= h*1.2f*0.75f*2.0f;
844 if ( m_bClosable ) width -= h*1.2f*0.75f;
845
846 pos.x = m_pos.x+0.01f;
847 dim.x = width-0.02f;
848 pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
849 dim.y = h*1.2f;
850 DrawVertex(pos, dim, (m_state&STATE_ENABLE)?2:9);
851
852 float sw = m_engine->GetText()->GetStringWidth(m_name, m_fontType, m_fontSize);
853
854 if ( m_state&STATE_ENABLE )
855 {
856 pos.x = m_pos.x+0.015f;
857 dim.x = (width-sw-0.06f)/2.0f;
858 pos.y = m_pos.y+m_dim.y-0.01f-h*1.0f;
859 dim.y = h*0.8f;
860 DrawHach(pos, dim); // left hatch
861 pos.x = m_pos.x+width-dim.x-0.015f;
862 DrawHach(pos, dim); // right hatch
863 }
864
865 pos.x = m_pos.x+width/2.0f;
866 pos.y = m_pos.y+m_dim.y-0.01f-h*1.10f;
867 m_engine->GetText()->DrawText(m_name, m_fontType, m_fontSize, pos, width, Gfx::TEXT_ALIGN_CENTER, 0);
868
869 if (m_buttonReduce != nullptr)
870 {
871 m_buttonReduce->Draw();
872 }
873
874 if (m_buttonFull != nullptr)
875 {
876 m_buttonFull->Draw();
877 }
878
879 if (m_buttonClose != nullptr)
880 {
881 m_buttonClose->Draw();
882 }
883 }
884
885 for (auto& control : m_controls)
886 {
887 control->Draw();
888 }
889 }
890
891 // Draws a rectangle.
892
DrawVertex(Math::Point pos,Math::Point dim,int icon)893 void CWindow::DrawVertex(Math::Point pos, Math::Point dim, int icon)
894 {
895 Math::Point p1, p2, uv1, uv2, corner;
896 float dp;
897 int i;
898
899 dp = 0.5f/256.0f;
900
901 if ( icon == 0 )
902 {
903 m_engine->SetTexture("textures/interface/button2.png");
904 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
905 uv1.x = 64.0f/256.0f; // dark blue transparent
906 uv1.y = 64.0f/256.0f;
907 uv2.x = 128.0f/256.0f;
908 uv2.y = 128.0f/256.0f;
909 uv1.x += dp;
910 uv1.y += dp;
911 uv2.x -= dp;
912 uv2.y -= dp;
913 corner.x = 14.0f/640.0f;
914 corner.y = 14.0f/480.0f;
915 DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
916 }
917 else if ( icon == 1 )
918 {
919 m_engine->SetTexture("textures/interface/button1.png");
920 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
921 uv1.x = 128.0f/256.0f; // white tooltip
922 uv1.y = 0.0f/256.0f;
923 uv2.x = 224.0f/256.0f;
924 uv2.y = 16.0f/256.0f;
925 uv1.x += dp;
926 uv1.y += dp;
927 uv2.x -= dp;
928 uv2.y -= dp;
929 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
930 }
931 else if ( icon == 2 )
932 {
933 m_engine->SetTexture("textures/interface/button1.png");
934 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
935 uv1.x = 128.0f/256.0f; // yellow
936 uv1.y = 16.0f/256.0f;
937 uv2.x = 224.0f/256.0f;
938 uv2.y = 32.0f/256.0f;
939 uv1.x += dp;
940 uv1.y += dp;
941 uv2.x -= dp;
942 uv2.y -= dp;
943 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
944 }
945 else if ( icon == 3 )
946 {
947 m_engine->SetTexture("textures/interface/button2.png");
948 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
949 uv1.x = 0.0f/256.0f; // transparent blue bar with yellow upper
950 uv1.y = 64.0f/256.0f;
951 uv2.x = 64.0f/256.0f;
952 uv2.y = 128.0f/256.0f;
953 uv1.x += dp;
954 uv1.y += dp;
955 uv2.x -= dp;
956 uv2.y -= dp;
957 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
958 }
959 else if ( icon == 4 ) // SatCom ?
960 {
961 pos.x -= 50.0f/640.0f;
962 pos.y -= 30.0f/480.0f;
963 dim.x += 100.0f/640.0f;
964 dim.y += 60.0f/480.0f;
965
966 m_engine->SetTexture("textures/objects/human.png");
967 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
968 uv1.x = 140.0f/256.0f;
969 uv1.y = 32.0f/256.0f;
970 uv2.x = 182.0f/256.0f;
971 uv2.y = 64.0f/256.0f;
972 uv1.x += dp;
973 uv1.y += dp;
974 uv2.x -= dp;
975 uv2.y -= dp;
976 DrawIcon(pos, dim, uv1, uv2); // clothing
977
978 pos.x += 20.0f/640.0f;
979 pos.y -= 10.0f/480.0f;
980 dim.x -= 20.0f/640.0f;
981 dim.y += 0.0f/480.0f;
982
983 m_engine->SetTexture("textures/interface/button2.png");
984 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);
985 uv1.x = 192.0f/256.0f;
986 uv1.y = 32.0f/256.0f;
987 uv2.x = 224.0f/256.0f;
988 uv2.y = 64.0f/256.0f;
989 uv1.x += dp;
990 uv1.y += dp;
991 uv2.x -= dp;
992 uv2.y -= dp;
993 corner.x = 30.0f/640.0f;
994 corner.y = 30.0f/480.0f;
995 DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f); // shadow
996
997 pos.x += 0.0f/640.0f;
998 pos.y += 20.0f/480.0f;
999 dim.x -= 20.0f/640.0f;
1000 dim.y -= 20.0f/480.0f;
1001
1002 m_engine->SetTexture("textures/interface/button1.png");
1003 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1004 uv1.x = 64.0f/256.0f;
1005 uv1.y = 0.0f/256.0f;
1006 uv2.x = 96.0f/256.0f;
1007 uv2.y = 32.0f/256.0f;
1008 uv1.x += dp;
1009 uv1.y += dp;
1010 uv2.x -= dp;
1011 uv2.y -= dp;
1012 corner.x = 14.0f/640.0f;
1013 corner.y = 14.0f/480.0f;
1014 DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f); // outside blue
1015
1016 pos.x += 20.0f/640.0f;
1017 pos.y += 10.0f/480.0f;
1018 dim.x -= 40.0f/640.0f;
1019 dim.y -= 20.0f/480.0f;
1020
1021 uv1.x = 96.0f/256.0f;
1022 uv1.y = 0.0f/256.0f;
1023 uv2.x = 128.0f/256.0f;
1024 uv2.y = 32.0f/256.0f;
1025 uv1.x += dp;
1026 uv1.y += dp;
1027 uv2.x -= dp;
1028 uv2.y -= dp;
1029 corner.x = 14.0f/640.0f;
1030 corner.y = 14.0f/480.0f;
1031 DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f); // inside blue
1032
1033 pos.x += 10.0f/640.0f;
1034 pos.y += 10.0f/480.0f;
1035 dim.x -= 20.0f/640.0f;
1036 dim.y -= 20.0f/480.0f;
1037
1038 m_engine->SetTexture("textures/interface/button3.png");
1039 uv1.x = 0.0f/256.0f;
1040 uv1.y = 224.0f/256.0f;
1041 uv2.x = 32.0f/256.0f;
1042 uv2.y = 256.0f/256.0f;
1043 uv1.x += dp;
1044 uv1.y += dp;
1045 uv2.x -= dp;
1046 uv2.y -= dp;
1047 DrawIcon(pos, dim, uv1, uv2); // dark blue background
1048
1049 m_engine->SetTexture("textures/interface/button2.png");
1050 uv1.x = 224.0f/256.0f;
1051 uv1.y = 224.0f/256.0f;
1052 uv2.x = 249.0f/256.0f;
1053 uv2.y = 235.0f/256.0f;
1054 uv1.x += dp;
1055 uv1.y += dp;
1056 uv2.x -= dp;
1057 uv2.y -= dp;
1058 pos.x = 20.0f/640.0f;
1059 pos.y = 70.0f/480.0f;
1060 dim.x = 25.0f/640.0f;
1061 dim.y = 11.0f/480.0f;
1062 for ( i=0 ; i<5 ; i++ )
1063 {
1064 DrawIcon(pos, dim, uv1, uv2); // = bottom/left
1065 pos.y += 15.0f/480.0f;
1066 }
1067 pos.y = (480.0f-70.0f-11.0f)/480.0f;
1068 for ( i=0 ; i<5 ; i++ )
1069 {
1070 DrawIcon(pos, dim, uv1, uv2); // = top/left
1071 pos.y -= 15.0f/480.0f;
1072 }
1073 pos.x = (640.0f-25.0f-20.0f)/640.0f;
1074 pos.y = 70.0f/480.0f;
1075 for ( i=0 ; i<5 ; i++ )
1076 {
1077 DrawIcon(pos, dim, uv1, uv2); // = bottom/right
1078 pos.y += 15.0f/480.0f;
1079 }
1080 pos.y = (480.0f-70.0f-11.0f)/480.0f;
1081 for ( i=0 ; i<5 ; i++ )
1082 {
1083 DrawIcon(pos, dim, uv1, uv2); // = top/right
1084 pos.y -= 15.0f/480.0f;
1085 }
1086
1087 uv1.x = 208.0f/256.0f;
1088 uv1.y = 224.0f/256.0f;
1089 uv2.x = 224.0f/256.0f;
1090 uv2.y = 240.0f/256.0f;
1091 uv1.x += dp;
1092 uv1.y += dp;
1093 uv2.x -= dp;
1094 uv2.y -= dp;
1095 dim.x = 10.0f/640.0f;
1096 dim.y = 10.0f/480.0f;
1097 pos.x = 534.0f/640.0f;
1098 pos.y = 430.0f/480.0f;
1099 for ( i=0 ; i<3 ; i++ )
1100 {
1101 DrawIcon(pos, dim, uv1, uv2); // micro
1102 pos.x += 12.0f/640.0f;
1103 }
1104 pos.x = 528.0f/640.0f;
1105 pos.y -= 12.0f/480.0f;
1106 for ( i=0 ; i<4 ; i++ )
1107 {
1108 DrawIcon(pos, dim, uv1, uv2); // micro
1109 pos.x += 12.0f/640.0f;
1110 }
1111 pos.x = 534.0f/640.0f;
1112 pos.y -= 12.0f/480.0f;
1113 for ( i=0 ; i<3 ; i++ )
1114 {
1115 DrawIcon(pos, dim, uv1, uv2); // micro
1116 pos.x += 12.0f/640.0f;
1117 }
1118 }
1119 else if ( icon == 5 )
1120 {
1121 m_engine->SetTexture("textures/interface/button2.png");
1122 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
1123 uv1.x = 64.0f/256.0f; // transparent green
1124 uv1.y = 160.0f/256.0f;
1125 uv2.x = 160.0f/256.0f;
1126 uv2.y = 176.0f/256.0f;
1127 uv1.x += dp;
1128 uv1.y += dp;
1129 uv2.x -= dp;
1130 uv2.y -= dp;
1131 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
1132 }
1133 else if ( icon == 6 )
1134 {
1135 m_engine->SetTexture("textures/interface/button2.png");
1136 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
1137 uv1.x = 64.0f/256.0f; // transparent red
1138 uv1.y = 176.0f/256.0f;
1139 uv2.x = 160.0f/256.0f;
1140 uv2.y = 192.0f/256.0f;
1141 uv1.x += dp;
1142 uv1.y += dp;
1143 uv2.x -= dp;
1144 uv2.y -= dp;
1145 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
1146 }
1147 else if ( icon == 7 )
1148 {
1149 m_engine->SetTexture("textures/interface/button2.png");
1150 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
1151 uv1.x = 64.0f/256.0f; // transparent blue
1152 uv1.y = 192.0f/256.0f;
1153 uv2.x = 160.0f/256.0f;
1154 uv2.y = 208.0f/256.0f;
1155 uv1.x += dp;
1156 uv1.y += dp;
1157 uv2.x -= dp;
1158 uv2.y -= dp;
1159 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
1160 }
1161 else if ( icon == 8 )
1162 {
1163 m_engine->SetTexture("textures/interface/button1.png");
1164 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1165 uv1.x = 0.0f/256.0f; // opaque orange
1166 uv1.y = 0.0f/256.0f;
1167 uv2.x = 32.0f/256.0f;
1168 uv2.y = 32.0f/256.0f;
1169 uv1.x += dp;
1170 uv1.y += dp;
1171 uv2.x -= dp;
1172 uv2.y -= dp;
1173 corner.x = 14.0f/640.0f;
1174 corner.y = 14.0f/480.0f;
1175 DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
1176 }
1177 else if ( icon == 9 )
1178 {
1179 m_engine->SetTexture("textures/interface/button2.png");
1180 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1181 uv1.x = 32.0f/256.0f; // opaque gray
1182 uv1.y = 32.0f/256.0f;
1183 uv2.x = 64.0f/256.0f;
1184 uv2.y = 64.0f/256.0f;
1185 uv1.x += dp;
1186 uv1.y += dp;
1187 uv2.x -= dp;
1188 uv2.y -= dp;
1189 corner.x = 14.0f/640.0f;
1190 corner.y = 14.0f/480.0f;
1191 DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
1192 }
1193 else if ( icon == 10 )
1194 {
1195 // nothing (in the background image)!
1196 }
1197 else if ( icon == 11 )
1198 {
1199 m_engine->SetTexture("textures/interface/button2.png");
1200 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_BLACK);
1201 uv1.x = 64.0f/256.0f; // transparent yellow
1202 uv1.y = 224.0f/256.0f;
1203 uv2.x = 160.0f/256.0f;
1204 uv2.y = 240.0f/256.0f;
1205 uv1.x += dp;
1206 uv1.y += dp;
1207 uv2.x -= dp;
1208 uv2.y -= dp;
1209 DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
1210 }
1211 else if ( icon == 12 )
1212 {
1213 m_engine->SetTexture("textures/interface/button1.png");
1214 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1215 uv1.x = 128.0f/256.0f; // dirty opaque gray
1216 uv1.y = 128.0f/256.0f;
1217 uv2.x = 160.0f/256.0f;
1218 uv2.y = 160.0f/256.0f;
1219 uv1.x += dp;
1220 uv1.y += dp;
1221 uv2.x -= dp;
1222 uv2.y -= dp;
1223 corner.x = 6.0f/640.0f;
1224 corner.y = 6.0f/480.0f;
1225 DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f);
1226 }
1227 else if ( icon == 13 )
1228 {
1229 m_engine->SetTexture("textures/interface/button1.png");
1230 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1231 uv1.x = 192.0f/256.0f; // dirty opaque blue
1232 uv1.y = 128.0f/256.0f;
1233 uv2.x = 224.0f/256.0f;
1234 uv2.y = 160.0f/256.0f;
1235 uv1.x += dp;
1236 uv1.y += dp;
1237 uv2.x -= dp;
1238 uv2.y -= dp;
1239 corner.x = 6.0f/640.0f;
1240 corner.y = 6.0f/480.0f;
1241 DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f);
1242 }
1243 else if ( icon == 14 )
1244 {
1245 m_engine->SetTexture("textures/interface/button1.png");
1246 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1247 uv1.x = 160.0f/256.0f; // dirty opaque red
1248 uv1.y = 128.0f/256.0f;
1249 uv2.x = 192.0f/256.0f;
1250 uv2.y = 160.0f/256.0f;
1251 uv1.x += dp;
1252 uv1.y += dp;
1253 uv2.x -= dp;
1254 uv2.y -= dp;
1255 corner.x = 6.0f/640.0f;
1256 corner.y = 6.0f/480.0f;
1257 DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f);
1258 }
1259 }
1260
1261 // Draws hatching.
1262
DrawHach(Math::Point pos,Math::Point dim)1263 void CWindow::DrawHach(Math::Point pos, Math::Point dim)
1264 {
1265 Math::Point ppos, ddim, uv1, uv2;
1266 float dp, max, ndim;
1267 bool bStop;
1268
1269 dp = 0.5f/256.0f;
1270
1271 m_engine->SetTexture("textures/interface/button2.png");
1272 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
1273 uv1.x = 64.0f/256.0f; // hatching
1274 uv1.y = 208.0f/256.0f;
1275 uv2.x = 145.0f/256.0f;
1276 uv2.y = 224.0f/256.0f;
1277 uv1.x += dp;
1278 uv1.y += dp;
1279 uv2.x -= dp;
1280 uv2.y -= dp;
1281
1282 max = dim.y*(uv2.x-uv1.x)/(uv2.y-uv1.y);
1283
1284 ppos = pos;
1285 ddim = dim;
1286 bStop = false;
1287 do
1288 {
1289 ddim.x = max;
1290 if ( ppos.x+ddim.x > pos.x+dim.x )
1291 {
1292 ndim = pos.x+dim.x-ppos.x;
1293 uv2.x = uv1.x+(uv2.x-uv1.x)*(ndim/ddim.x);
1294 ddim.x = ndim;
1295 bStop = true;
1296 }
1297 DrawIcon(ppos, ddim, uv1, uv2);
1298
1299 ppos.x += ddim.x;
1300 }
1301 while ( !bStop );
1302 }
1303
SetFocus(CControl * focusControl)1304 void CWindow::SetFocus(CControl* focusControl)
1305 {
1306 for (auto& control : m_controls)
1307 {
1308 if (control != nullptr)
1309 {
1310 control->SetFocus(focusControl);
1311 }
1312 }
1313 }
1314
1315 }
1316