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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
24 | CheckListWidget::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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
50 | void CheckListWidget::handleMouseEntered() |
51 | { |
52 | setFlags(Widget::FLAG_HILITED); |
53 | setDirty(); |
54 | } |
55 | |
56 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
57 | void CheckListWidget::handleMouseLeft() |
58 | { |
59 | clearFlags(Widget::FLAG_HILITED); |
60 | setDirty(); |
61 | } |
62 | |
63 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
64 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
84 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
94 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
150 | Common::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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
160 | bool 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
169 | bool 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
184 | void 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 | |