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/list.h"
22
23 #include "common/make_unique.h"
24
25 #include "graphics/engine/engine.h"
26
27 #include <cassert>
28 #include <cstring>
29
30 namespace Ui
31 {
32
33 const float MARGING = 4.0f;
34
35
36 // Object's constructor.
37
CList()38 CList::CList()
39 : CControl(),
40 m_tabs(),
41 m_justifs()
42 {
43 for (int i = 0; i < 10; i++)
44 {
45 m_tabs[i] = 0.0f;
46 m_justifs[i] = Gfx::TEXT_ALIGN_LEFT;
47 }
48
49 m_expand = 0.0f;
50 m_totalLine = 0;
51 m_displayLine = 0;
52 m_selectLine = -1;
53 m_firstLine = 0;
54 m_bBlink = false;
55 m_bSelectCap = true;
56 m_blinkTime = 0.0f;
57 }
58
59 // Object's destructor.
60
~CList()61 CList::~CList()
62 {
63 }
64
65
66 // Creates a new list.
67 // if expand is less then zero, then the list would try to use expand's absolute value,
68 // and try to scale items to some size, so that dim of the list would not change after
69 // adjusting
70
Create(Math::Point pos,Math::Point dim,int icon,EventType eventMsg,float expand)71 bool CList::Create(Math::Point pos, Math::Point dim, int icon, EventType eventMsg, float expand)
72 {
73 m_expand = expand;
74
75 if (eventMsg == EVENT_NULL)
76 eventMsg = GetUniqueEventType();
77
78 CControl::Create(pos, dim, icon, eventMsg);
79
80 m_scroll = MakeUnique<CScroll>();
81 m_scroll->Create(pos, dim, 0, EVENT_NULL);
82
83 return MoveAdjust();
84 }
85
86 // Should never be called
Create(Math::Point pos,Math::Point dim,int icon,EventType eventType)87 bool CList::Create(Math::Point pos, Math::Point dim, int icon, EventType eventType)
88 {
89 assert(false);
90 return false;
91 }
92
93
94 // Adjusted after a change of dimensions.
95
MoveAdjust()96 bool CList::MoveAdjust()
97 {
98 Math::Point ipos, idim, ppos, ddim;
99 float marging, h;
100
101 for (auto& button : m_buttons)
102 button.reset();
103
104 if (m_icon == 0)
105 marging = MARGING;
106 else
107 marging = 0.0f;
108
109 ipos.x = m_pos.x + marging / 640.f;
110 ipos.y = m_pos.y + marging / 480.f;
111 idim.x = m_dim.x - marging * 2.0f / 640.f;
112 idim.y = m_dim.y - marging * 2.0f / 480.f;
113
114 //If m_expand is less then zero, then try to apply it's absolute value
115 h = m_engine->GetText()->GetHeight(m_fontType, m_fontSize) * ((m_expand < 0) ? -m_expand : m_expand);
116 m_displayLine = static_cast<int>(idim.y / h);
117
118 if (m_displayLine == 0)
119 return false;
120 if (m_displayLine > LISTMAXDISPLAY)
121 m_displayLine = LISTMAXDISPLAY;
122
123 // Stretch lines to fill whole area of a list, if needed
124 if (m_expand < 0 && (idim.y - (h * m_displayLine) < h))
125 {
126 h = idim.y / m_displayLine;
127 }
128
129 idim.y = h * m_displayLine; //Here cuts list size if height of shown elements is less then designed height
130 m_dim.y = idim.y + marging * 2.0f / 480.f;
131
132 ppos.x = ipos.x;
133 ppos.y = ipos.y + idim.y - h;
134 ddim.x = idim.x - SCROLL_WIDTH;
135 ddim.y = h;
136 for (int i = 0; i < m_displayLine; i++)
137 {
138 auto button = MakeUnique<CButton>();
139 button->Create(ppos, ddim, -1, EVENT_NULL);
140 button->SetTextAlign(Gfx::TEXT_ALIGN_LEFT);
141 button->SetState(STATE_SIMPLY);
142 button->SetFontType(m_fontType);
143 button->SetFontSize(m_fontSize);
144 ppos.y -= h;
145
146 m_buttons[i] = std::move(button);
147 }
148
149 if (m_scroll != nullptr)
150 {
151 ppos.x = ipos.x + idim.x - SCROLL_WIDTH;
152 ppos.y = ipos.y;
153 ddim.x = SCROLL_WIDTH;
154 ddim.y = idim.y;
155 m_scroll->SetPos(ppos);
156 m_scroll->SetDim(ddim);
157 }
158
159 UpdateScroll();
160 UpdateButton();
161 return true;
162 }
163
164
165 // Returns the message of a button.
166
GetEventMsgButton(int i)167 EventType CList::GetEventMsgButton(int i)
168 {
169 if (i < 0 || i >= m_displayLine)
170 return EVENT_NULL;
171 if (m_buttons[i] == nullptr)
172 return EVENT_NULL;
173 return m_buttons[i]->GetEventType();
174 }
175
176 // Returns the message from the elevator.
177
GetEventMsgScroll()178 EventType CList::GetEventMsgScroll()
179 {
180 if (m_scroll == nullptr)
181 return EVENT_NULL;
182 return m_scroll->GetEventType();
183 }
184
185
SetPos(Math::Point pos)186 void CList::SetPos(Math::Point pos)
187 {
188 CControl::SetPos(pos);
189 }
190
191
SetDim(Math::Point dim)192 void CList::SetDim(Math::Point dim)
193 {
194 m_dim = dim;
195 MoveAdjust();
196 CControl::SetDim(dim);
197 }
198
199
SetState(int state,bool bState)200 bool CList::SetState(int state, bool bState)
201 {
202 if (state & STATE_ENABLE)
203 {
204 for (int i = 0; i < m_displayLine; i++)
205 {
206 if (m_buttons[i] != nullptr)
207 m_buttons[i]->SetState(state, bState);
208 }
209 if (m_scroll != nullptr)
210 m_scroll->SetState(state, bState);
211 }
212
213 return CControl::SetState(state, bState);
214 }
215
216
SetState(int state)217 bool CList::SetState(int state)
218 {
219 if (state & STATE_ENABLE)
220 {
221 for (int i = 0; i < m_displayLine; i++)
222 {
223 if (m_buttons[i] != nullptr)
224 m_buttons[i]->SetState(state);
225 }
226 if (m_scroll != nullptr)
227 m_scroll->SetState(state);
228 }
229
230 return CControl::SetState(state);
231 }
232
233
ClearState(int state)234 bool CList::ClearState(int state)
235 {
236 if (state & STATE_ENABLE)
237 {
238 for (int i = 0; i < m_displayLine; i++)
239 {
240 if (m_buttons[i] != nullptr)
241 m_buttons[i]->ClearState(state);
242 }
243 if (m_scroll != nullptr)
244 m_scroll->ClearState(state);
245 }
246
247 return CControl::ClearState(state);
248 }
249
250
251 // Management of an event.
252
EventProcess(const Event & event)253 bool CList::EventProcess(const Event &event)
254 {
255 if (m_bBlink && event.type == EVENT_FRAME)
256 {
257 int i = m_selectLine-m_firstLine;
258
259 if (i >= 0 && i < 4 && m_buttons[i] != nullptr)
260 {
261 m_blinkTime += event.rTime;
262 if (Math::Mod(m_blinkTime, 0.7f) < 0.3f)
263 {
264 m_buttons[i]->ClearState(STATE_ENABLE);
265 m_buttons[i]->ClearState(STATE_CHECK);
266 }
267 else
268 {
269 m_buttons[i]->SetState(STATE_ENABLE);
270 m_buttons[i]->SetState(STATE_CHECK);
271 }
272 }
273 }
274
275 if ((m_state & STATE_VISIBLE) == 0)
276 return true;
277 if ((m_state & STATE_ENABLE) == 0)
278 return true;
279
280 if (event.type == EVENT_MOUSE_WHEEL && Detect(event.mousePos))
281 {
282 auto data = event.GetData<MouseWheelEventData>();
283 m_firstLine -= data->y;
284 if (m_firstLine > m_totalLine - m_displayLine)
285 m_firstLine = m_totalLine - m_displayLine;
286 if (m_firstLine < 0)
287 m_firstLine = 0;
288
289 UpdateScroll();
290 UpdateButton();
291 return false;
292 }
293
294 CControl::EventProcess(event);
295
296 if (event.type == EVENT_MOUSE_MOVE || event.type == EVENT_MOUSE_BUTTON_DOWN || event.type == EVENT_MOUSE_BUTTON_UP)
297 {
298 if (Detect(event.mousePos))
299 {
300 m_engine->SetMouseType(Gfx::ENG_MOUSE_NORM);
301 for (int i = 0; i < m_displayLine; i++)
302 {
303 if (i + m_firstLine >= m_totalLine)
304 break;
305 if (m_buttons[i] != nullptr)
306 m_buttons[i]->EventProcess(event);
307 }
308 }
309 }
310
311 if (m_bSelectCap)
312 {
313 for (int i = 0; i < m_displayLine; i++)
314 {
315 if (i + m_firstLine >= m_totalLine)
316 break;
317
318 if (m_buttons[i] != nullptr)
319 {
320 if (!m_buttons[i]->EventProcess(event))
321 return false;
322
323 if (event.type == m_buttons[i]->GetEventType())
324 {
325 SetSelect(m_firstLine + i);
326
327 m_event->AddEvent(Event(m_eventType)); // selected line changes
328 }
329 }
330 }
331 }
332
333 if (m_scroll != nullptr)
334 {
335 if (!m_scroll->EventProcess(event))
336 return false;
337
338 if (event.type == m_scroll->GetEventType())
339 {
340 MoveScroll();
341 UpdateButton();
342 }
343 }
344
345 return true;
346 }
347
348
349 // Draws the list.
350
Draw()351 void CList::Draw()
352 {
353 Math::Point uv1, uv2, corner, pos, dim, ppos, ddim;
354 float dp;
355 int i;
356 char text[100];
357 const char *pb, *pe;
358
359 if ((m_state & STATE_VISIBLE) == 0)
360 return;
361
362 if (m_state & STATE_SHADOW)
363 DrawShadow(m_pos, m_dim);
364
365 dp = 0.5f / 256.0f;
366
367 if (m_icon != -1)
368 {
369 dim = m_dim;
370
371 if (m_icon == 0)
372 {
373 m_engine->SetTexture("textures/interface/button2.png");
374 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
375
376 uv1.x = 128.0f / 256.0f;
377 uv1.y = 64.0f / 256.0f; // u-v texture
378 uv2.x = 160.0f / 256.0f;
379 uv2.y = 96.0f / 256.0f;
380 }
381 else
382 {
383 m_engine->SetTexture("textures/interface/button2.png");
384 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
385
386 uv1.x = 132.0f / 256.0f;
387 uv1.y = 68.0f / 256.0f; // u-v texture
388 uv2.x = 156.0f / 256.0f;
389 uv2.y = 92.0f / 256.0f;
390
391 if (m_buttons[0] != nullptr)
392 {
393 dim = m_buttons[0]->GetDim();
394 dim.y *= m_displayLine; // background sounds spot behind
395 }
396 }
397
398 uv1.x += dp;
399 uv1.y += dp;
400 uv2.x -= dp;
401 uv2.y -= dp;
402
403 corner.x = 10.0f / 640.0f;
404 corner.y = 10.0f / 480.0f;
405 DrawIcon(m_pos, dim, uv1, uv2, corner, 8.0f / 256.0f);
406 }
407
408 if ( m_totalLine < m_displayLine ) // no buttons to the bottom?
409 {
410 i = m_totalLine;
411 if (m_buttons[i] != nullptr)
412 {
413 pos = m_buttons[i]->GetPos();
414 dim = m_buttons[i]->GetDim();
415 pos.y += dim.y * 1.1f;
416 dim.y *= 0.4f;
417 pos.y -= dim.y;
418
419 m_engine->SetTexture("textures/interface/button2.png");
420 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); // was D3DSTATETTw
421 uv1.x = 120.0f / 256.0f;
422 uv1.y = 64.0f / 256.0f;
423 uv2.x = 128.0f / 256.0f;
424 uv2.y = 48.0f / 256.0f;
425 uv1.x += dp;
426 uv1.y -= dp;
427 uv2.x -= dp;
428 uv2.y += dp;
429 DrawIcon(pos, dim, uv1, uv2); // ch'tite shadow cute (?)
430 }
431 }
432
433 for (i = 0; i < m_displayLine; i++)
434 {
435 if ( i + m_firstLine >= m_totalLine )
436 break;
437
438 if ( m_buttons[i] != nullptr )
439 {
440 if ( !m_bBlink && i + m_firstLine < m_totalLine )
441 m_buttons[i]->SetState(STATE_ENABLE, m_items[i+m_firstLine].enable && (m_state & STATE_ENABLE) );
442
443 m_buttons[i]->Draw(); // draws a box without text
444
445 // draws text in the box
446 pos = m_buttons[i]->GetPos();
447 dim = m_buttons[i]->GetDim();
448 if ( m_tabs[0] == 0.0f )
449 {
450 ppos.x = pos.x + dim.y * 0.5f;
451 ppos.y = pos.y + dim.y * 0.5f;
452 ppos.y -= m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f;
453 ddim.x = dim.x-dim.y;
454 DrawCase(m_items[i + m_firstLine].text.c_str(), ppos, ddim.x, Gfx::TEXT_ALIGN_LEFT);
455 }
456 else
457 {
458 ppos.x = pos.x + dim.y * 0.5f;
459 ppos.y = pos.y + dim.y * 0.5f;
460 ppos.y -= m_engine->GetText()->GetHeight(m_fontType, m_fontSize) / 2.0f;
461 pb = m_items[i + m_firstLine].text.c_str();
462 for (int j = 0; j < 10; j++)
463 {
464 pe = strchr(pb, '\t');
465 if ( pe == nullptr )
466 strcpy(text, pb);
467 else
468 {
469 strncpy(text, pb, pe - pb);
470 text[pe - pb] = 0;
471 }
472 DrawCase(text, ppos, m_tabs[j], m_justifs[j]);
473
474 if ( pe == nullptr )
475 break;
476 ppos.x += m_tabs[j];
477 pb = pe + 1;
478 }
479 }
480
481 if ( (m_state & STATE_EXTEND) && i < m_totalLine)
482 {
483 pos = m_buttons[i]->GetPos();
484 dim = m_buttons[i]->GetDim();
485 pos.x += dim.x - dim.y * 0.75f;
486 dim.x = dim.y * 0.75f;
487 pos.x += 2.0f / 640.0f;
488 pos.y += 2.0f / 480.0f;
489 dim.x -= 4.0f / 640.0f;
490 dim.y -= 4.0f / 480.0f;
491
492 if (m_items[i + m_firstLine].check)
493 {
494 m_engine->SetTexture("textures/interface/button1.png");
495 m_engine->SetState(Gfx::ENG_RSTATE_NORMAL);
496 uv1.x = 64.0f / 256.0f;
497 uv1.y = 0.0f / 256.0f;
498 uv2.x = 96.0f / 256.0f;
499 uv2.y = 32.0f / 256.0f;
500 uv1.x += dp;
501 uv1.y += dp;
502 uv2.x -= dp;
503 uv2.y -= dp;
504 DrawIcon(pos, dim, uv1, uv2); // square shape
505
506 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); // was D3DSTATETTw
507 uv1.x = 0.0f / 256.0f; // v
508 uv1.y = 64.0f / 256.0f;
509 uv2.x = 32.0f / 256.0f;
510 uv2.y = 96.0f / 256.0f;
511 uv1.x += dp;
512 uv1.y += dp;
513 uv2.x -= dp;
514 uv2.y -= dp;
515 DrawIcon(pos, dim, uv1, uv2); // draws v
516 }
517 else
518 {
519 m_engine->SetTexture("textures/interface/button1.png");
520 m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE); // was D3DSTATETTw
521 if ( i + m_firstLine == m_selectLine )
522 {
523 uv1.x =224.0f / 256.0f; // <
524 uv1.y =192.0f / 256.0f;
525 uv2.x =256.0f / 256.0f;
526 uv2.y =224.0f / 256.0f;
527 }
528 else
529 {
530 uv1.x = 96.0f / 256.0f; // x
531 uv1.y = 32.0f / 256.0f;
532 uv2.x =128.0f / 256.0f;
533 uv2.y = 64.0f / 256.0f;
534 }
535 uv1.x += dp;
536 uv1.y += dp;
537 uv2.x -= dp;
538 uv2.y -= dp;
539 DrawIcon(pos, dim, uv1, uv2); // draws x
540 }
541 }
542 }
543 }
544
545 if (m_scroll != nullptr)
546 m_scroll->Draw(); // draws the lift
547 }
548
549 // Displays text in a box.
550
DrawCase(const char * text,Math::Point pos,float width,Gfx::TextAlign justif)551 void CList::DrawCase(const char* text, Math::Point pos, float width, Gfx::TextAlign justif)
552 {
553 if (justif == Gfx::TEXT_ALIGN_CENTER)
554 pos.x += width / 2.0f;
555 else if (justif == Gfx::TEXT_ALIGN_RIGHT)
556 pos.x += width;
557 m_engine->GetText()->DrawText(std::string(text), m_fontType, m_fontSize, pos, width, justif, 0);
558 }
559
560
561 // Empty the list completely.
562
Flush()563 void CList::Flush()
564 {
565 m_totalLine = 0;
566 m_selectLine = -1;
567 m_firstLine = 0;
568 UpdateButton();
569 UpdateScroll();
570 }
571
572
573 // Specifies the total number of lines.
574
SetTotal(int i)575 void CList::SetTotal(int i)
576 {
577 m_totalLine = i;
578 }
579
580 // Returns the total number of lines.
581
GetTotal()582 int CList::GetTotal()
583 {
584 return m_totalLine;
585 }
586
587
588 // Selects a line.
589
SetSelect(int i)590 void CList::SetSelect(int i)
591 {
592 if ( m_bSelectCap )
593 m_selectLine = i;
594 else
595 {
596 m_firstLine = i;
597 UpdateScroll();
598 }
599
600 UpdateButton();
601 }
602
603 // Returns the selected line.
604
GetSelect()605 int CList::GetSelect()
606 {
607 if ( m_bSelectCap )
608 return m_selectLine;
609 else
610 return m_firstLine;
611 }
612
613
614 // Management of capability has a select box.
615
SetSelectCap(bool bEnable)616 void CList::SetSelectCap(bool bEnable)
617 {
618 m_bSelectCap = bEnable;
619 }
620
GetSelectCap()621 bool CList::GetSelectCap()
622 {
623 return m_bSelectCap;
624 }
625
626
627 // Blink a line.
628
SetBlink(bool bEnable)629 void CList::SetBlink(bool bEnable)
630 {
631 m_bBlink = bEnable;
632 m_blinkTime = 0.0f;
633
634 int i = m_selectLine - m_firstLine;
635
636 if (i >= 0 && i < 4 && m_buttons[i] != nullptr)
637 {
638 if ( !bEnable )
639 {
640 m_buttons[i]->SetState(STATE_CHECK);
641 m_buttons[i]->ClearState(STATE_ENABLE);
642 }
643 }
644 }
645
GetBlink()646 bool CList::GetBlink()
647 {
648 return m_bBlink;
649 }
650
651
652 // Specifies the text of a line.
653
SetItemName(int i,const std::string & name)654 void CList::SetItemName(int i, const std::string& name)
655 {
656 if ( i < 0 )
657 return;
658
659 if ( i >= m_totalLine )
660 m_totalLine = i+1; // expands the list
661
662 m_items.resize(m_totalLine);
663 if ( name.empty() )
664 m_items[i].text = " ";
665 else
666 m_items[i].text = name;
667
668 UpdateButton();
669 UpdateScroll();
670 }
671
672 // Returns the text of a line.
673
GetItemName(int i)674 const std::string& CList::GetItemName(int i)
675 {
676 if ( i < 0 || i >= m_totalLine )
677 assert(false);
678
679 return m_items[i].text;
680 }
681
682
683 // Specifies the bit "check" for a box.
684
SetCheck(int i,bool bMode)685 void CList::SetCheck(int i, bool bMode)
686 {
687 if ( i < 0 || i >= m_totalLine )
688 return;
689
690 m_items[i].check = bMode;
691 }
692
693 // Returns the bit "check" for a box.
694
GetCheck(int i)695 bool CList::GetCheck(int i)
696 {
697 if ( i < 0 || i >= m_totalLine )
698 return false;
699
700 return m_items[i].check;
701 }
702
703
704 // Specifies the bit "enable" for a box.
705
SetEnable(int i,bool enable)706 void CList::SetEnable(int i, bool enable)
707 {
708 if ( i < 0 || i >= m_totalLine )
709 return;
710
711 m_items[i].enable = enable;
712 }
713
714 // Returns the bit "enable" for a box.
715
GetEnable(int i)716 bool CList::GetEnable(int i)
717 {
718 if ( i < 0 || i >= m_totalLine )
719 return false;
720
721 return m_items[i].enable;
722 }
723
724
725 // Management of the position of the tabs.
726
SetTabs(int i,float pos,Gfx::TextAlign justif)727 void CList::SetTabs(int i, float pos, Gfx::TextAlign justif)
728 {
729 if ( i < 0 || i >= 10 )
730 return;
731 m_tabs[i] = pos;
732 m_justifs[i] = justif;
733 }
734
GetTabs(int i)735 float CList::GetTabs(int i)
736 {
737 if ( i < 0 || i >= 10 )
738 return 0.0f;
739 return m_tabs[i];
740 }
741
742
743 // Moves the lift to see the list of the selected line.
744
ShowSelect(bool bFixed)745 void CList::ShowSelect(bool bFixed)
746 {
747 int sel;
748
749 if ( bFixed && m_selectLine >= m_firstLine && m_selectLine < m_firstLine+m_displayLine )
750 return; // all good
751
752 sel = m_selectLine;
753
754 // Down from 1/2 * h.
755 sel += m_displayLine / 2;
756 if ( sel > m_totalLine - 1 )
757 sel = m_totalLine - 1;
758
759 // Back to h-1.
760 sel -= m_displayLine - 1;
761 if ( sel < 0 )
762 sel = 0;
763
764 m_firstLine = sel;
765
766 UpdateButton();
767 UpdateScroll();
768 }
769
770
771 // Updates all button names.
772
UpdateButton()773 void CList::UpdateButton()
774 {
775 int state, i, j;
776
777 state = CControl::GetState();
778
779 j = m_firstLine;
780 for (i = 0; i < m_displayLine; i++)
781 {
782 if (m_buttons[i] == nullptr)
783 continue;
784
785 m_buttons[i]->SetState(STATE_CHECK, (j == m_selectLine));
786
787 if ( j < m_totalLine )
788 {
789 //? m_buttons[i]->SetName(m_text[j]);
790 m_buttons[i]->SetName(" "); // blank button
791 m_buttons[i]->SetState(STATE_ENABLE, (state & STATE_ENABLE));
792 }
793 else
794 {
795 m_buttons[i]->SetName(" "); // blank button
796 m_buttons[i]->ClearState(STATE_ENABLE);
797 }
798 j ++;
799 }
800 }
801
802 // Updates the lift.
803
UpdateScroll()804 void CList::UpdateScroll()
805 {
806 float ratio, value, step;
807
808 if (m_scroll == nullptr)
809 return;
810
811 if (m_totalLine <= m_displayLine)
812 {
813 ratio = 1.0f;
814 value = 0.0f;
815 step = 0.0f;
816 }
817 else
818 {
819 ratio = static_cast<float>(m_displayLine) / m_totalLine;
820 if ( ratio > 1.0f ) ratio = 1.0f;
821
822 value = static_cast<float>(m_firstLine) / (m_totalLine - m_displayLine);
823 if ( value < 0.0f )
824 value = 0.0f;
825 if ( value > 1.0f )
826 value = 1.0f;
827
828 step = static_cast<float>(1.0f)/ (m_totalLine - m_displayLine);
829 if ( step < 0.0f )
830 step = 0.0f;
831 }
832
833 m_scroll->SetVisibleRatio(ratio);
834 m_scroll->SetVisibleValue(value);
835 m_scroll->SetArrowStep(step);
836 }
837
838 // Update when the lift is moving.
839
MoveScroll()840 void CList::MoveScroll()
841 {
842 if (m_scroll == nullptr)
843 return;
844
845 int n = m_totalLine - m_displayLine;
846 float pos = m_scroll->GetVisibleValue();
847 pos += m_scroll->GetArrowStep() / 2.0f; // it's magic!
848 m_firstLine = static_cast<int>(pos * n);
849 if ( m_firstLine < 0 )
850 m_firstLine = 0;
851 if ( m_firstLine > n )
852 m_firstLine = n;
853 }
854
855
856 } // namespace Ui
857