1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "Dialog.hxx"
19#include "FBSurface.hxx"
20#include "ScrollBarWidget.hxx"
21#include "CheckListWidget.hxx"
22
23// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24CheckListWidget::CheckListWidget(GuiObject* boss, const GUI::Font& font,
25 int x, int y, int w, int h)
26 : ListWidget(boss, font, x, y, w, h)
27{
28 int ypos = _y + 2;
29
30 // rowheight is determined by largest item on a line,
31 // possibly meaning that number of rows will change
32 _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize());
33 _rows = h / _fontHeight;
34
35 // Create a CheckboxWidget for each row in the list
36 for(int i = 0; i < _rows; ++i)
37 {
38 CheckboxWidget* t = new CheckboxWidget(boss, font, _x + 2, ypos, "",
39 CheckboxWidget::kCheckActionCmd);
40 t->setTextColor(kTextColor);
41 t->setTarget(this);
42 t->setID(i);
43 ypos += _fontHeight;
44
45 _checkList.push_back(t);
46 }
47}
48
49// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
50void CheckListWidget::handleMouseEntered()
51{
52 setFlags(Widget::FLAG_HILITED);
53 setDirty();
54}
55
56// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
57void CheckListWidget::handleMouseLeft()
58{
59 clearFlags(Widget::FLAG_HILITED);
60 setDirty();
61}
62
63// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
64void CheckListWidget::setList(const StringList& list, const BoolArray& state)
65{
66 _list = list;
67 _stateList = state;
68
69 assert(_list.size() == _stateList.size());
70
71 // Enable all checkboxes
72 for(int i = 0; i < _rows; ++i)
73 _checkList[i]->setFlags(Widget::FLAG_ENABLED);
74
75 // Then turn off any extras
76 if(int(_stateList.size()) < _rows)
77 for(int i = int(_stateList.size()); i < _rows; ++i)
78 _checkList[i]->clearFlags(Widget::FLAG_ENABLED);
79
80 ListWidget::recalc();
81}
82
83// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
84void CheckListWidget::setLine(int line, const string& str, const bool& state)
85{
86 if(line >= int(_list.size()))
87 return;
88
89 _list[line] = str;
90 _stateList[line] = state;
91}
92
93// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
94void CheckListWidget::drawWidget(bool hilite)
95{
96//cerr << "CheckListWidget::drawWidget\n";
97 FBSurface& s = _boss->dialog().surface();
98 bool onTop = _boss->dialog().isOnTop();
99 int i, pos, len = int(_list.size());
100
101 // Draw a thin frame around the list and to separate columns
102 s.frameRect(_x, _y, _w, _h, hilite ? kWidColorHi : kColor);
103 s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor);
104
105 // Draw the list items
106 for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++)
107 {
108 // Draw checkboxes for correct lines (takes scrolling into account)
109 _checkList[i]->setState(_stateList[pos]);
110 _checkList[i]->setDirty();
111 _checkList[i]->draw();
112
113 const int y = _y + 2 + _fontHeight * i + 2;
114 ColorId textColor = kTextColor;
115
116 Common::Rect r(getEditRect());
117
118 // Draw the selected item inverted, on a highlighted background.
119 if (_selectedItem == pos)
120 {
121 if(_hasFocus && !_editMode)
122 {
123 s.fillRect(_x + r.x() - 3, _y + 1 + _fontHeight * i,
124 _w - r.x(), _fontHeight, kTextColorHi);
125 textColor = kTextColorInv;
126 }
127 else
128 s.frameRect(_x + r.x() - 3, _y + 1 + _fontHeight * i,
129 _w - r.x(), _fontHeight, onTop ? kTextColorHi : kColor);
130 }
131
132 if (_selectedItem == pos && _editMode)
133 {
134 adjustOffset();
135 s.drawString(_font, editString(), _x + r.x(), y, r.w(), onTop ? kTextColor : kColor,
136 TextAlign::Left, -_editScrollOffset, false);
137 }
138 else
139 s.drawString(_font, _list[pos], _x + r.x(), y, r.w(),
140 onTop ? textColor : kColor);
141 }
142
143 // Only draw the caret while editing, and if it's in the current viewport
144 if(_editMode && (_selectedItem >= _scrollBar->_currentPos) &&
145 (_selectedItem < _scrollBar->_currentPos + _rows))
146 drawCaret();
147}
148
149// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
150Common::Rect CheckListWidget::getEditRect() const
151{
152 const int yoffset = (_selectedItem - _currentPos) * _fontHeight,
153 xoffset = CheckboxWidget::boxSize() + 10;
154
155 return Common::Rect(2 + xoffset, 1 + yoffset,
156 _w - (xoffset - 15), _fontHeight + yoffset);
157}
158
159// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
160bool CheckListWidget::getState(int line)
161{
162 if(line >= 0 && line < int(_stateList.size()))
163 return _stateList[line];
164 else
165 return false;
166}
167
168// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
169bool CheckListWidget::handleEvent(Event::Type e)
170{
171 switch(e)
172 {
173 case Event::UISelect:
174 // Simulate a mouse button click
175 _checkList[ListWidget::getSelected()]->handleMouseUp(0, 0, MouseButton::LEFT, 0);
176 return true;
177
178 default:
179 return ListWidget::handleEvent(e);
180 }
181}
182
183// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
184void CheckListWidget::handleCommand(CommandSender* sender, int cmd,
185 int data, int id)
186{
187 switch(cmd)
188 {
189 case CheckboxWidget::kCheckActionCmd:
190 {
191 // Figure out which line has been checked
192 int line = _currentPos + id;
193 _stateList[line] = bool(data);
194
195 // Let the boss know about it
196 sendCommand(CheckListWidget::kListItemChecked, line, _id);
197 break;
198 }
199
200 default:
201 ListWidget::handleCommand(sender, cmd, data, id);
202 break;
203 }
204}
205