1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "bladerunner/ui/ui_scroll_box.h"
24
25 #include "bladerunner/audio_player.h"
26 #include "bladerunner/bladerunner.h"
27 #include "bladerunner/font.h"
28 #include "bladerunner/game_info.h"
29 #include "bladerunner/shape.h"
30 #include "bladerunner/time.h"
31 #include "bladerunner/game_constants.h"
32 #include "bladerunner/ui/kia.h"
33
34 namespace BladeRunner {
35
36 const Color256 UIScrollBox::k3DFrameColors[] = {
37 { 32, 32, 24 },
38 { 40, 40, 40 },
39 { 40, 40, 48 },
40 { 72, 64, 64 },
41 { 160, 136, 128 },
42 { 160, 136, 128 },
43 { 0, 0, 0 },
44 { 0, 0, 0 }
45 };
46 const Color256 UIScrollBox::kTextBackgroundColors[] = {
47 { 40, 56, 80 },
48 { 48, 64, 96 },
49 { 56, 72, 112 },
50 { 72, 88, 128 },
51 { 152, 192, 248 },
52 { 0, 0, 0 }
53 };
54 const Color256 UIScrollBox::kTextColors1[] = {
55 { 72, 104, 152 },
56 { 96, 120, 184 },
57 { 112, 144, 216 },
58 { 136, 168, 248 },
59 { 152, 192, 248 }
60 };
61 const Color256 UIScrollBox::kTextColors2[] = {
62 { 200, 216, 248 },
63 { 216, 224, 248 },
64 { 224, 232, 248 },
65 { 232, 240, 248 },
66 { 248, 248, 248 }
67 };
68 const Color256 UIScrollBox::kTextColors3[] = {
69 { 240, 232, 192 },
70 { 240, 232, 208 },
71 { 240, 240, 216 },
72 { 248, 240, 232 },
73 { 248, 248, 248 }
74 };
75 const Color256 UIScrollBox::kTextColors4[] = {
76 { 152, 112, 56 },
77 { 184, 144, 88 },
78 { 216, 184, 112 },
79 { 232, 208, 136 },
80 { 248, 224, 144 }
81 };
82
UIScrollBox(BladeRunnerEngine * vm,UIScrollBoxClickedCallback * lineSelectedCallback,void * callbackData,int maxLineCount,int style,bool center,Common::Rect rect,Common::Rect scrollBarRect)83 UIScrollBox::UIScrollBox(BladeRunnerEngine *vm,
84 UIScrollBoxClickedCallback *lineSelectedCallback,
85 void *callbackData,
86 int maxLineCount,
87 int style,
88 bool center,
89 Common::Rect rect,
90 Common::Rect scrollBarRect) : UIComponent(vm) {
91
92 _selectedLineState = 0;
93 _scrollUpButtonState = 0;
94 _scrollDownButtonState = 0;
95 _scrollAreaUpState = 0;
96 _scrollAreaDownState = 0;
97 _scrollBarState = 0;
98
99 _scrollUpButtonHover = false;
100 _scrollDownButtonHover = false;
101 _scrollAreaUpHover = false;
102 _scrollAreaDownHover = false;
103 _scrollBarHover = false;
104
105 _hoveredLine = -1;
106 _selectedLineIndex = -1;
107
108 _lineSelectedCallback = lineSelectedCallback;
109 _callbackData = callbackData;
110
111 _isVisible = false;
112 _style = style; // 0, 1 or (new) 2. "2" is similar to "1" but with solid background for main area and scroll bar
113 _center = center;
114 _timeLastScroll = _vm->_time->currentSystem();
115 _timeLastCheckbox = _vm->_time->currentSystem();
116 _timeLastHighlight = _vm->_time->currentSystem();
117
118 _highlightFrame = 0;
119
120 _rect = rect;
121 _scrollBarRect = scrollBarRect;
122 _scrollBarRect.right += 15; // right side was not used, but it's useful for determining if the control is selected
123
124 _lineCount = 0;
125 _maxLineCount = maxLineCount;
126
127 _firstLineVisible = 0;
128 _maxLinesVisible = _rect.height() / kLineHeight;
129
130 _mouseButton = false;
131
132 _rect.bottom = _rect.top + kLineHeight * _maxLinesVisible - 1;
133
134 _lines.resize(_maxLineCount);
135 for (int i = 0; i < _maxLineCount; ++i) {
136 _lines[i] = new Line();
137 _lines[i]->lineData = -1;
138 _lines[i]->flags = 0x00;
139 _lines[i]->checkboxFrame = 5u;
140 }
141
142 _mouseOver = false;
143 }
144
~UIScrollBox()145 UIScrollBox::~UIScrollBox() {
146 for (int i = 0; i < _maxLineCount; ++i) {
147 delete _lines[i];
148 }
149 }
150
show()151 void UIScrollBox::show() {
152 _selectedLineState = 0;
153 _scrollUpButtonState = 0;
154 _scrollDownButtonState = 0;
155 _scrollAreaUpState = 0;
156 _scrollAreaDownState = 0;
157 _scrollBarState = 0;
158
159 _hoveredLine = -1;
160 _selectedLineIndex = -1;
161
162 _scrollUpButtonHover = false;
163 _scrollDownButtonHover = false;
164 _scrollAreaUpHover = false;
165 _scrollAreaDownHover = false;
166 _scrollBarHover = false;
167
168 _timeLastScroll = _vm->_time->currentSystem();
169 _timeLastCheckbox = _vm->_time->currentSystem();
170 _timeLastHighlight = _vm->_time->currentSystem();
171
172 _highlightFrame = 0;
173 _isVisible = true;
174
175 _mouseOver = false;
176 }
177
hide()178 void UIScrollBox::hide() {
179 _isVisible = false;
180 }
181
isVisible()182 bool UIScrollBox::isVisible() {
183 return _isVisible;
184 }
185
hasFocus()186 bool UIScrollBox::hasFocus() {
187 return _mouseOver;
188 }
189
setBoxTop(int top)190 void UIScrollBox::setBoxTop(int top) {
191 _rect.moveTo(_rect.left, top);
192
193 _rect.bottom = _rect.top + kLineHeight * _maxLinesVisible - 1;
194 }
195
setBoxLeft(int left)196 void UIScrollBox::setBoxLeft(int left) {
197 _rect.moveTo(left, _rect.top);
198 }
199
setBoxWidth(uint16 width)200 void UIScrollBox::setBoxWidth(uint16 width) {
201 _rect.setWidth(width);
202 }
203
getBoxLeft()204 int UIScrollBox::getBoxLeft() {
205 return _rect.left;
206 }
207
getBoxWidth()208 uint16 UIScrollBox::getBoxWidth() {
209 return _rect.width();
210 }
211
setScrollbarTop(int top)212 void UIScrollBox::setScrollbarTop(int top) {
213 _scrollBarRect.moveTo(_scrollBarRect.left, top);
214 }
215
setScrollbarLeft(int left)216 void UIScrollBox::setScrollbarLeft(int left) {
217 _scrollBarRect.moveTo(left, _scrollBarRect.top);
218 }
219
setScrollbarWidth(uint16 width)220 void UIScrollBox::setScrollbarWidth(uint16 width) {
221 _scrollBarRect.setWidth(width);
222 _scrollBarRect.right += 15; // right side was not used, but it's useful for determining if the control is selected
223 }
224
clearLines()225 void UIScrollBox::clearLines() {
226 _lineCount = 0;
227 _firstLineVisible = 0;
228 }
229
addLine(const Common::String & text,int lineData,int flags)230 void UIScrollBox::addLine(const Common::String &text, int lineData, int flags) {
231 _lines[_lineCount]->text = text;
232 _lines[_lineCount]->lineData = lineData;
233 _lines[_lineCount]->flags = flags;
234
235 ++_lineCount;
236 }
237
addLine(const char * text,int lineData,int flags)238 void UIScrollBox::addLine(const char *text, int lineData, int flags) {
239 _lines[_lineCount]->text = text;
240 _lines[_lineCount]->lineData = lineData;
241 _lines[_lineCount]->flags = flags;
242
243 ++_lineCount;
244 }
245
sortLines()246 void UIScrollBox::sortLines() {
247 qsort(_lines.data(), _lineCount, sizeof(Line *), &sortFunction);
248 }
249
handleMouseMove(int mouseX,int mouseY)250 void UIScrollBox::handleMouseMove(int mouseX, int mouseY) {
251 if (!_isVisible) {
252 return;
253 }
254
255 _mouseOver = _rect.contains(mouseX, mouseY) || _scrollBarRect.contains(mouseX, mouseY);
256
257 if (_rect.contains(mouseX, mouseY)) {
258 int newHoveredLine = (mouseY - _rect.top) / 10 + _firstLineVisible;
259 if (newHoveredLine >= _lineCount) {
260 newHoveredLine = -1;
261 }
262
263 if (newHoveredLine != _hoveredLine && newHoveredLine >= 0 && newHoveredLine < _lineCount) {
264 if (_lines[newHoveredLine]->lineData >= 0 && _selectedLineState == 0) {
265 int soundId = kSfxTEXT1;
266 if (_lines[newHoveredLine]->flags & 0x01 ) {
267 soundId = kSfxTEXT3;
268 }
269 _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 100, 0, 0, 50, 0);
270 }
271 }
272 _hoveredLine = newHoveredLine;
273 } else {
274 _hoveredLine = -1;
275 }
276
277 _scrollUpButtonHover =
278 (mouseX >= _scrollBarRect.left)
279 && (mouseX < _scrollBarRect.left + 15)
280 && (mouseY >= _scrollBarRect.top)
281 && (mouseY < _scrollBarRect.top + 8);
282
283 _scrollDownButtonHover =
284 (mouseX >= _scrollBarRect.left)
285 && (mouseX < _scrollBarRect.left + 15)
286 && (mouseY > _scrollBarRect.bottom - 8)
287 && (mouseY <= _scrollBarRect.bottom);
288
289 int scrollAreaHeight = _scrollBarRect.bottom - _scrollBarRect.top - 15;
290
291 int scrollBarHeight = scrollAreaHeight;
292 if (_lineCount > _maxLinesVisible) {
293 scrollBarHeight = _maxLinesVisible * scrollAreaHeight / _lineCount;
294 }
295 if (scrollBarHeight < 16) {
296 scrollBarHeight = 16;
297 }
298
299 int scrollAreaEmptySize = scrollAreaHeight - scrollBarHeight;
300
301 int scrollBarY = 0;
302 if (_lineCount > _maxLinesVisible) {
303 scrollBarY = scrollAreaEmptySize * _firstLineVisible / (_lineCount - _maxLinesVisible);
304 }
305
306 if (_scrollBarState == 2) {
307 int v12 = scrollBarHeight / 2 + 8;
308 if (mouseY - _scrollBarRect.top > v12 && _lineCount > _maxLinesVisible && scrollAreaEmptySize > 0) {
309 _firstLineVisible = (_lineCount - _maxLinesVisible) * (mouseY - _scrollBarRect.top - v12) / scrollAreaEmptySize;
310 if (_firstLineVisible > _lineCount - _maxLinesVisible) {
311 _firstLineVisible = _lineCount - _maxLinesVisible;
312 }
313 } else {
314 _firstLineVisible = 0;
315 }
316
317 if (_lineCount <= _maxLinesVisible) {
318 scrollBarY = 0;
319 } else {
320 scrollBarY = scrollAreaEmptySize * _firstLineVisible/ (_lineCount - _maxLinesVisible);
321 }
322 }
323 scrollBarY = scrollBarY + _scrollBarRect.top + 8;
324
325 _scrollBarHover =
326 (mouseX >= _scrollBarRect.left)
327 && (mouseX < _scrollBarRect.left + 15)
328 && (mouseY >= scrollBarY)
329 && (mouseY < scrollBarY + scrollBarHeight);
330
331 _scrollAreaUpHover =
332 (mouseX >= _scrollBarRect.left)
333 && (mouseX < _scrollBarRect.left + 15)
334 && (mouseY >= _scrollBarRect.top + 8)
335 && (mouseY < scrollBarY);
336
337 _scrollAreaDownHover =
338 (mouseX >= _scrollBarRect.left)
339 && (mouseX < _scrollBarRect.left + 15)
340 && (mouseY >= scrollBarY + scrollBarHeight)
341 && (mouseY < _scrollBarRect.bottom - 8);
342 }
343
handleMouseDown(bool alternateButton)344 void UIScrollBox::handleMouseDown(bool alternateButton) {
345 if (!_isVisible) {
346 return;
347 }
348
349 _mouseButton = alternateButton;
350 if (_hoveredLine == -1) {
351 _selectedLineState = 1;
352 } else if (_selectedLineIndex == -1) {
353 _selectedLineIndex = _hoveredLine;
354 _selectedLineState = 2;
355 if (_hoveredLine < _lineCount) {
356 if (_lineSelectedCallback) {
357 _lineSelectedCallback(_callbackData, this, _lines[_selectedLineIndex]->lineData, _mouseButton);
358 }
359
360 if (_lines[_selectedLineIndex]->flags & 0x01) {
361 _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxBEEP10), 100, 0, 0, 50, 0);
362 }
363 }
364 }
365 if (!alternateButton) {
366 if (_scrollUpButtonHover) {
367 _scrollUpButtonState = 2;
368 _timeLastScroll = _vm->_time->currentSystem() - 160u;
369 } else {
370 _scrollUpButtonState = 1;
371 }
372 if (_scrollDownButtonHover) {
373 _scrollDownButtonState = 2;
374 } else {
375 _scrollDownButtonState = 1;
376 }
377 if (_scrollBarHover) {
378 _scrollBarState = 2;
379 } else {
380 _scrollBarState = 1;
381 }
382 if (_scrollAreaUpHover) {
383 _scrollAreaUpState = 2;
384 _timeLastScroll = _vm->_time->currentSystem() - 160u;
385 } else {
386 _scrollAreaUpState = 1;
387 }
388 if (_scrollAreaDownHover) {
389 _scrollAreaDownState = 2;
390 _timeLastScroll = _vm->_time->currentSystem() - 160u;
391 } else {
392 _scrollAreaDownState = 1;
393 }
394 }
395 }
396
handleMouseUp(bool alternateButton)397 void UIScrollBox::handleMouseUp(bool alternateButton) {
398 if (_isVisible) {
399 if ( alternateButton == _mouseButton) {
400 _selectedLineState = 0;
401 _selectedLineIndex = -1;
402 }
403
404 if (!alternateButton) {
405 _scrollUpButtonState = 0;
406 _scrollDownButtonState = 0;
407 _scrollAreaUpState = 0;
408 _scrollAreaDownState = 0;
409 _scrollBarState = 0;
410 }
411 }
412 }
413
handleMouseScroll(int direction)414 void UIScrollBox::handleMouseScroll(int direction) {
415 if (_mouseOver) {
416 if (direction > 0) {
417 scrollDown();
418 } else if (direction < 0) {
419 scrollUp();
420 }
421 }
422 }
423
getSelectedLineData()424 int UIScrollBox::getSelectedLineData() {
425 if (_hoveredLine >= 0 && _selectedLineState != 1 && _hoveredLine < _lineCount) {
426 return _lines[_hoveredLine]->lineData;
427 }
428 return -1;
429 }
430
getLineText(int lineData)431 Common::String UIScrollBox::getLineText(int lineData) {
432 if (hasLine(lineData)) {
433 return _lines[_hoveredLine]->text;
434 }
435 return "";
436 }
437
getMaxLinesVisible()438 int UIScrollBox::getMaxLinesVisible() {
439 return _maxLinesVisible;
440 }
441
getLineCount()442 int UIScrollBox::getLineCount() {
443 return _lineCount;
444 }
445
draw(Graphics::Surface & surface)446 void UIScrollBox::draw(Graphics::Surface &surface) {
447 if (!_isVisible) {
448 return;
449 }
450
451 uint32 timeNow = _vm->_time->currentSystem();
452
453 // update scrolling
454 if (_scrollUpButtonState == 2 && _scrollUpButtonHover) {
455 // unsigned difference is intentional
456 if ((timeNow - _timeLastScroll) > 160u) {
457 scrollUp();
458 _timeLastScroll = timeNow;
459 }
460 } else if (_scrollDownButtonState == 2 && _scrollDownButtonHover) {
461 // unsigned difference is intentional
462 if ((timeNow - _timeLastScroll) > 160u) {
463 scrollDown();
464 _timeLastScroll = timeNow;
465 }
466 } else if (_scrollAreaUpState == 2 && _scrollAreaUpHover) {
467 // unsigned difference is intentional
468 if ((timeNow - _timeLastScroll) > 160u) {
469 _firstLineVisible -= _maxLinesVisible - 1;
470 _firstLineVisible = CLIP(_firstLineVisible, 0, _lineCount - _maxLinesVisible);
471 _timeLastScroll = timeNow;
472 }
473 } else if (_scrollAreaDownState == 2 && _scrollAreaDownHover) {
474 // unsigned difference is intentional
475 if ((timeNow - _timeLastScroll) > 160u) {
476 _firstLineVisible += _maxLinesVisible - 1;
477 _firstLineVisible = CLIP(_firstLineVisible, 0, _lineCount - _maxLinesVisible);
478 _timeLastScroll = timeNow;
479 }
480 }
481
482 // update checkboxes
483 // unsigned difference is intentional
484 uint32 timeDiffCheckBox = timeNow - _timeLastCheckbox;
485 if (timeDiffCheckBox > 67u) {
486 _timeLastCheckbox = timeNow;
487 for (int i = 0; i < _lineCount; ++i) {
488 if (_lines[i]->flags & 0x01) { // has checkbox
489 if (_lines[i]->flags & 0x02) { // checkbox checked
490 if (_lines[i]->checkboxFrame < 5u) {
491 _lines[i]->checkboxFrame += timeDiffCheckBox / 67u;
492 }
493 if (_lines[i]->checkboxFrame > 5u) {
494 _lines[i]->checkboxFrame = 5u;
495 }
496 } else { // checkbox not checked
497 if (_lines[i]->checkboxFrame > 0u) {
498 _lines[i]->checkboxFrame = (_lines[i]->checkboxFrame < (timeDiffCheckBox / 67u)) ? 0u : _lines[i]->checkboxFrame - (timeDiffCheckBox / 67u);
499 }
500 if (_lines[i]->checkboxFrame == 0u) { // original was < 0, int
501 _lines[i]->checkboxFrame = 0u;
502 }
503 }
504 }
505 }
506 }
507
508
509 // update highlight
510 // unsigned difference is intentional
511 if ((timeNow - _timeLastHighlight) > 67u) {
512 _timeLastHighlight = timeNow;
513 _highlightFrame = (_highlightFrame + 1) % 8;
514 }
515
516 // draw text lines
517 int linesVisible = 0;
518 int lastLineVisible = 0;
519
520 if (_maxLinesVisible < _lineCount - _firstLineVisible) {
521 linesVisible = _maxLinesVisible;
522 lastLineVisible = _firstLineVisible + _maxLinesVisible;
523 } else {
524 linesVisible = _lineCount - _firstLineVisible;
525 lastLineVisible = _lineCount;
526 }
527
528 if (_firstLineVisible < lastLineVisible) {
529 int y = _rect.top;
530 int y1 = _rect.top + 8;
531 int y2 = _rect.top + 2;
532 int i = _firstLineVisible;
533 do {
534 int startingColorIndex = 3;
535 if (i - _firstLineVisible < 3) {
536 startingColorIndex = i - _firstLineVisible;
537 }
538
539 int endingColorIndex = 3;
540 if (i - _firstLineVisible >= linesVisible - 3) {
541 endingColorIndex = linesVisible - (i - _firstLineVisible + 1);
542 }
543
544 int colorIndex = endingColorIndex;
545 if (startingColorIndex < endingColorIndex) {
546 colorIndex = startingColorIndex;
547 }
548
549 bool v35 = false;
550 int color = 0;
551
552 if ((((_selectedLineState == 0 && i == _hoveredLine) || (_selectedLineState == 2 && i == _selectedLineIndex && _selectedLineIndex == _hoveredLine)) && _lines[i]->lineData != -1) || _lines[i]->flags & 0x04) {
553 v35 = true;
554 if (_style) {
555 color = surface.format.RGBToColor(kTextColors2[colorIndex].r, kTextColors2[colorIndex].g, kTextColors2[colorIndex].b);
556 } else {
557 color = surface.format.RGBToColor(kTextColors3[colorIndex].r, kTextColors3[colorIndex].g, kTextColors3[colorIndex].b);
558 }
559 }
560 else {
561 if (_style) {
562 color = surface.format.RGBToColor(kTextColors1[colorIndex].r, kTextColors1[colorIndex].g, kTextColors1[colorIndex].b);
563 } else {
564 color = surface.format.RGBToColor(kTextColors4[colorIndex].r, kTextColors4[colorIndex].g, kTextColors4[colorIndex].b);
565 }
566 }
567
568 int x = _rect.left;
569
570 if (_lines[i]->flags & 0x01) { // has checkbox
571 int checkboxShapeId = 0;
572 if (_style == 0) {
573 if (_lines[i]->checkboxFrame || v35) {
574 if (_lines[i]->checkboxFrame != 5u || v35) {
575 checkboxShapeId = _lines[i]->checkboxFrame + 62u;
576 } else {
577 checkboxShapeId = 61;
578 }
579 } else {
580 checkboxShapeId = 60;
581 }
582 } else if (_lines[i]->checkboxFrame || v35) {
583 if (_lines[i]->checkboxFrame != 5u || v35) {
584 checkboxShapeId = _lines[i]->checkboxFrame + 54u;
585 } else {
586 checkboxShapeId = 53;
587 }
588 } else {
589 checkboxShapeId = 52;
590 }
591 _vm->_kia->_shapes->get(checkboxShapeId)->draw(surface, x - 1, y);
592 x += 11;
593 }
594
595 if (_lines[i]->flags & 0x10) { // highlighted line
596 if (_lines[i]->flags & 0x20) {
597 int highlightShapeId = _highlightFrame;
598 if (highlightShapeId > 4) {
599 highlightShapeId = 8 - highlightShapeId;
600 }
601 _vm->_kia->_shapes->get(highlightShapeId + 85)->draw(surface, x, y2);
602 }
603 x += 6;
604 }
605
606 if (_lines[i]->flags & 0x08) { // has background rectangle
607 int colorBackground = 0;
608 if (_vm->_cutContent && (_lines[i]->flags & 0x40)) {
609 // A KIA clue marked as hidden/private, but already shared with Mainframe
610 // Note, proper hidden clues will not have this mark and will get colorBackground
611 // from below (case _style > 0)
612 colorBackground = surface.format.RGBToColor(80, 46, 22);
613 } else {
614 if (_style == 2) {
615 colorBackground = surface.format.RGBToColor(kTextBackgroundColors[colorIndex].r / 8, kTextBackgroundColors[colorIndex].g / 8, kTextBackgroundColors[colorIndex].b / 8);
616 } else if (_style > 0) {
617 colorBackground = surface.format.RGBToColor(kTextBackgroundColors[colorIndex].r, kTextBackgroundColors[colorIndex].g, kTextBackgroundColors[colorIndex].b);
618 } else {
619 colorBackground = surface.format.RGBToColor(80, 56, 32);
620 }
621 }
622
623 if (_style == 2) {
624 // New: style = 2 (original unused)
625 // original behavior -- No padding between the colored background of lines, simulate solid background (gradient)
626 surface.fillRect(Common::Rect(CLIP(x - 1, 0, 639), y, _rect.right + 1, y + kLineHeight), colorBackground);
627 } else {
628 // original behavior -- there is padding between the colored background of lines
629 surface.fillRect(Common::Rect(x, y, _rect.right + 1, y1 + 1), colorBackground);
630 }
631 }
632
633 if (_center) {
634 x = _rect.left + (_rect.width() - _vm->_mainFont->getStringWidth(_lines[i]->text)) / 2;
635 }
636
637 _vm->_mainFont->drawString(&surface, _lines[i]->text, x, y, surface.w, color);
638
639 y1 += kLineHeight;
640 y2 += kLineHeight;
641 y += kLineHeight;
642 ++i;
643 } while (i < lastLineVisible);
644 }
645
646 if (_style == 2 && getLineCount() >= getMaxLinesVisible()) {
647 // New: style = 2 (original unused)
648 // Solid background color for scrollbar
649 int scrollBarFillColor = surface.format.RGBToColor(k3DFrameColors[0].r / 2, k3DFrameColors[0].g / 2, k3DFrameColors[0].b / 2);
650 surface.fillRect(Common::Rect(_scrollBarRect.left, _scrollBarRect.top, CLIP(_scrollBarRect.left + 15, 0, 639), _scrollBarRect.bottom), scrollBarFillColor);
651 }
652
653 if (_style != 2
654 || (_style == 2 && getLineCount() >= getMaxLinesVisible())
655 ) {
656 // draw scroll up button
657 int scrollUpButtonShapeId = 0;
658 if (_scrollUpButtonState) {
659 if (_scrollUpButtonState == 2) {
660 if (_scrollUpButtonHover) {
661 scrollUpButtonShapeId = 72;
662 } else {
663 scrollUpButtonShapeId = 71;
664 }
665 } else {
666 scrollUpButtonShapeId = 70;
667 }
668 } else if (_scrollUpButtonHover) {
669 scrollUpButtonShapeId = 71;
670 } else {
671 scrollUpButtonShapeId = 70;
672 }
673 _vm->_kia->_shapes->get(scrollUpButtonShapeId)->draw(surface, _scrollBarRect.left, _scrollBarRect.top);
674
675 // draw scroll down button
676 int scrollDownButtonShapeId = 0;
677 if (_scrollDownButtonState) {
678 if (_scrollDownButtonState == 2) {
679 if (_scrollDownButtonHover) {
680 scrollDownButtonShapeId = 75;
681 } else {
682 scrollDownButtonShapeId = 74;
683 }
684 } else {
685 scrollDownButtonShapeId = 73;
686 }
687 } else if (_scrollDownButtonHover) {
688 scrollDownButtonShapeId = 74;
689 } else {
690 scrollDownButtonShapeId = 73;
691 }
692 _vm->_kia->_shapes->get(scrollDownButtonShapeId)->draw(surface, _scrollBarRect.left, _scrollBarRect.bottom - 7);
693
694 int scrollAreaSize = _scrollBarRect.bottom - (_scrollBarRect.top + 15);
695 int scrollBarHeight = 0;
696 if (_lineCount <= _maxLinesVisible) {
697 scrollBarHeight = _scrollBarRect.bottom - (_scrollBarRect.top + 15);
698 } else {
699 scrollBarHeight = _maxLinesVisible * scrollAreaSize / _lineCount;
700 }
701 scrollBarHeight = MAX(scrollBarHeight, 16);
702
703 int v56 = 0;
704 if (_lineCount <= _maxLinesVisible) {
705 v56 = 0;
706 } else {
707 v56 = _firstLineVisible * (scrollAreaSize - scrollBarHeight) / (_lineCount - _maxLinesVisible);
708 }
709
710 int v58 = v56 + _scrollBarRect.top + 8;
711
712 if (_scrollBarState == 2) {
713 draw3DFrame(surface, Common::Rect(_scrollBarRect.left, v58, _scrollBarRect.left + 15, v58 + scrollBarHeight), 1, 1);
714 } else if (!_scrollBarState && _scrollBarHover) {
715 draw3DFrame(surface, Common::Rect(_scrollBarRect.left, v56 + _scrollBarRect.top + 8, _scrollBarRect.left + 15, v58 + scrollBarHeight), 0, 1);
716 } else {
717 draw3DFrame(surface, Common::Rect(_scrollBarRect.left, v58, _scrollBarRect.left + 15, v58 + scrollBarHeight), 0, 0);
718 }
719 }
720 }
721
checkAll()722 void UIScrollBox::checkAll() {
723 for (int i = 0; i < _lineCount; ++i) {
724 if (_lines[i]->flags & 0x01) {
725 _lines[i]->flags |= 0x02;
726 }
727 }
728 }
729
uncheckAll()730 void UIScrollBox::uncheckAll() {
731 for (int i = 0; i < _lineCount; ++i) {
732 if (_lines[i]->flags & 0x01) {
733 _lines[i]->flags &= ~0x02;
734 }
735 }
736 }
737
toggleCheckBox(int lineData)738 void UIScrollBox::toggleCheckBox(int lineData) {
739 int i = findLine(lineData);
740 if (i != -1) {
741 if (_lines[i]->flags & 0x02) {
742 _lines[i]->flags &= ~0x02;
743 } else {
744 _lines[i]->flags |= 0x02;
745 }
746 }
747 }
748
hasLine(int lineData)749 bool UIScrollBox::hasLine(int lineData) {
750 return findLine(lineData) != -1;
751 }
752
resetHighlight(int lineData)753 void UIScrollBox::resetHighlight(int lineData) {
754 int i = findLine(lineData);
755 if (i != -1) {
756 _lines[i]->flags &= ~0x20;
757 }
758 }
759
setFlags(int lineData,int flags)760 void UIScrollBox::setFlags(int lineData, int flags) {
761 int i = findLine(lineData);
762 if (i != -1) {
763 _lines[i]->flags |= flags;
764 }
765 }
766
resetFlags(int lineData,int flags)767 void UIScrollBox::resetFlags(int lineData, int flags) {
768 int i = findLine(lineData);
769 if (i != -1) {
770 _lines[i]->flags &= ~flags;
771 }
772 }
773
sortFunction(const void * item1,const void * item2)774 int UIScrollBox::sortFunction(const void *item1, const void *item2) {
775 Line *line1 = *(Line * const *)item1;
776 Line *line2 = *(Line * const *)item2;
777 return line1->text.compareToIgnoreCase(line2->text);
778 }
779
draw3DFrame(Graphics::Surface & surface,Common::Rect rect,bool pressed,int style)780 void UIScrollBox::draw3DFrame(Graphics::Surface &surface, Common::Rect rect, bool pressed, int style) {
781 int color1, color2;
782
783 if (pressed) {
784 color1 = surface.format.RGBToColor(k3DFrameColors[style + 6].r, k3DFrameColors[style + 6].g, k3DFrameColors[style + 6].b);
785 color2 = surface.format.RGBToColor(k3DFrameColors[style + 4].r, k3DFrameColors[style + 4].g, k3DFrameColors[style + 4].b);
786 } else {
787 color1 = surface.format.RGBToColor(k3DFrameColors[style + 4].r, k3DFrameColors[style + 4].g, k3DFrameColors[style + 4].b);
788 color2 = surface.format.RGBToColor(k3DFrameColors[style + 6].r, k3DFrameColors[style + 6].g, k3DFrameColors[style + 6].b);
789 }
790
791 int color3 = surface.format.RGBToColor(k3DFrameColors[style].r, k3DFrameColors[style].g, k3DFrameColors[style].b);
792 int fillColor = surface.format.RGBToColor(k3DFrameColors[style + 2].r, k3DFrameColors[style + 2].g, k3DFrameColors[style + 2].b);
793
794 surface.fillRect(Common::Rect(rect.left + 1, rect.top + 1, rect.right - 1, rect.bottom - 1), fillColor);
795
796 surface.hLine(rect.left + 1, rect.top, rect.right - 2, color1);
797 surface.hLine(rect.left + 1, rect.bottom - 1, rect.right - 2, color2);
798 surface.vLine(rect.left, rect.top, rect.bottom - 2, color1);
799 surface.vLine(rect.right - 1, rect.top + 1, rect.bottom - 1, color2);
800 surface.hLine(rect.right - 1, rect.top, rect.right - 1, color3);
801 surface.hLine(rect.left, rect.bottom - 1, rect.left, color3);
802 }
803
scrollUp()804 void UIScrollBox::scrollUp() {
805 if (_firstLineVisible > 0) {
806 --_firstLineVisible;
807 }
808 }
809
scrollDown()810 void UIScrollBox::scrollDown() {
811 if (_lineCount - _firstLineVisible > _maxLinesVisible) {
812 ++_firstLineVisible;
813 }
814 }
815
findLine(int lineData)816 int UIScrollBox::findLine(int lineData) {
817 for (int i = 0; i < _lineCount; ++i) {
818 if (_lines[i]->lineData == lineData) {
819 return i;
820 }
821 }
822 return -1;
823 }
824
825 } // End of namespace BladeRunner
826