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 "Widget.hxx" |
19 | #include "Dialog.hxx" |
20 | #include "Font.hxx" |
21 | #include "Debugger.hxx" |
22 | #include "FrameBuffer.hxx" |
23 | #include "FBSurface.hxx" |
24 | #include "DataGridWidget.hxx" |
25 | #include "DataGridOpsWidget.hxx" |
26 | #include "RamWidget.hxx" |
27 | #include "ScrollBarWidget.hxx" |
28 | #include "StellaKeys.hxx" |
29 | |
30 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
31 | DataGridWidget::DataGridWidget(GuiObject* boss, const GUI::Font& font, |
32 | int x, int y, int cols, int rows, |
33 | int colchars, int bits, |
34 | Common::Base::Format base, |
35 | bool useScrollbar) |
36 | : EditableWidget(boss, font, x, y, |
37 | cols*(colchars * font.getMaxCharWidth() + 8) + 1, |
38 | font.getLineHeight()*rows + 1), |
39 | _rows(rows), |
40 | _cols(cols), |
41 | _currentRow(0), |
42 | _currentCol(0), |
43 | _rowHeight(font.getLineHeight()), |
44 | _colWidth(colchars * font.getMaxCharWidth() + 8), |
45 | _bits(bits), |
46 | _crossGrid(false), |
47 | _base(base), |
48 | _selectedItem(0), |
49 | _currentKeyDown(KBDK_UNKNOWN), |
50 | _opsWidget(nullptr), |
51 | _scrollBar(nullptr) |
52 | { |
53 | _flags = Widget::FLAG_ENABLED | Widget::FLAG_RETAIN_FOCUS | Widget::FLAG_WANTS_RAWDATA; |
54 | _editMode = false; |
55 | |
56 | // The item is selected, thus _bgcolor is used to draw the caret and |
57 | // _textcolorhi to erase it |
58 | _caretInverse = true; |
59 | |
60 | // Make sure all lists contain some default values |
61 | _hiliteList.clear(); |
62 | int size = _rows * _cols; |
63 | while(size--) |
64 | { |
65 | _addrList.push_back(0); |
66 | _valueList.push_back(0); |
67 | _valueStringList.push_back("" ); |
68 | _changedList.push_back(0); |
69 | _hiliteList.push_back(false); |
70 | } |
71 | |
72 | // Set lower and upper bounds to sane values |
73 | setRange(0, 1 << bits); |
74 | |
75 | // Add a scrollbar if necessary |
76 | if(useScrollbar) |
77 | { |
78 | _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); |
79 | _scrollBar->setTarget(this); |
80 | _scrollBar->_numEntries = 1; |
81 | _scrollBar->_currentPos = 0; |
82 | _scrollBar->_entriesPerPage = 1; |
83 | _scrollBar->_wheel_lines = 1; |
84 | } |
85 | |
86 | // Add filtering |
87 | EditableWidget::TextFilter f; |
88 | switch(base) |
89 | { |
90 | case Common::Base::F_16: |
91 | case Common::Base::F_16_1: |
92 | case Common::Base::F_16_2: |
93 | case Common::Base::F_16_4: |
94 | case Common::Base::F_16_8: |
95 | setTextFilter([](char c) { |
96 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); |
97 | }); |
98 | break; |
99 | case Common::Base::F_10: |
100 | setTextFilter([](char c) { |
101 | return (c >= '0' && c <= '9'); |
102 | }); |
103 | break; |
104 | case Common::Base::F_2: |
105 | case Common::Base::F_2_8: |
106 | case Common::Base::F_2_16: |
107 | setTextFilter([](char c) { return (c >= '0' && c <= '1'); }); |
108 | break; |
109 | default: |
110 | break; // no filtering for now |
111 | } |
112 | } |
113 | |
114 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
115 | void DataGridWidget::setList(const IntArray& alist, const IntArray& vlist, |
116 | const BoolArray& changed) |
117 | { |
118 | /* |
119 | cerr << "alist.size() = " << alist.size() |
120 | << ", vlist.size() = " << vlist.size() |
121 | << ", changed.size() = " << changed.size() |
122 | << ", _rows*_cols = " << _rows * _cols << endl << endl; |
123 | */ |
124 | int size = int(vlist.size()); // assume the alist is the same size |
125 | assert(size == _rows * _cols); |
126 | |
127 | _addrList.clear(); |
128 | _valueList.clear(); |
129 | _valueStringList.clear(); |
130 | _changedList.clear(); |
131 | |
132 | _addrList = alist; |
133 | _valueList = vlist; |
134 | _changedList = changed; |
135 | |
136 | // An efficiency thing |
137 | string temp; |
138 | for(int i = 0; i < size; ++i) |
139 | _valueStringList.push_back(Common::Base::toString(_valueList[i], _base)); |
140 | |
141 | /* |
142 | cerr << "_addrList.size() = " << _addrList.size() |
143 | << ", _valueList.size() = " << _valueList.size() |
144 | << ", _changedList.size() = " << _changedList.size() |
145 | << ", _valueStringList.size() = " << _valueStringList.size() |
146 | << ", _rows*_cols = " << _rows * _cols << endl << endl; |
147 | */ |
148 | enableEditMode(false); |
149 | |
150 | // Send item selected signal for starting with cell 0 |
151 | sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); |
152 | |
153 | setDirty(); |
154 | } |
155 | |
156 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
157 | void DataGridWidget::setList(int a, int v, bool c) |
158 | { |
159 | IntArray alist, vlist; |
160 | BoolArray changed; |
161 | |
162 | alist.push_back(a); |
163 | vlist.push_back(v); |
164 | changed.push_back(c); |
165 | |
166 | setList(alist, vlist, changed); |
167 | } |
168 | |
169 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
170 | void DataGridWidget::setList(int a, int v) |
171 | { |
172 | IntArray alist, vlist; |
173 | BoolArray changed; |
174 | |
175 | alist.push_back(a); |
176 | vlist.push_back(v); |
177 | bool diff = _addrList.size() == 1 ? getSelectedValue() != v : false; |
178 | changed.push_back(diff); |
179 | |
180 | setList(alist, vlist, changed); |
181 | } |
182 | |
183 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
184 | void DataGridWidget::setEditable(bool editable, bool hiliteBG) |
185 | { |
186 | // Override parent method; enable hilite when widget is not editable |
187 | EditableWidget::setEditable(editable, hiliteBG); |
188 | } |
189 | |
190 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
191 | void DataGridWidget::setHiliteList(const BoolArray& hilitelist) |
192 | { |
193 | assert(hilitelist.size() == uInt32(_rows * _cols)); |
194 | _hiliteList.clear(); |
195 | _hiliteList = hilitelist; |
196 | |
197 | setDirty(); |
198 | } |
199 | |
200 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
201 | void DataGridWidget::setNumRows(int rows) |
202 | { |
203 | if(_scrollBar) |
204 | _scrollBar->_numEntries = rows; |
205 | } |
206 | |
207 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
208 | void DataGridWidget::setSelectedValue(int value) |
209 | { |
210 | setValue(_selectedItem, value, _valueList[_selectedItem] != value); |
211 | } |
212 | |
213 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
214 | void DataGridWidget::setValue(int position, int value) |
215 | { |
216 | setValue(position, value, _valueList[position] != value); |
217 | } |
218 | |
219 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
220 | void DataGridWidget::setValueInternal(int position, int value, bool changed) |
221 | { |
222 | setValue(position, value, changed, false); |
223 | } |
224 | |
225 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
226 | void DataGridWidget::setValue(int position, int value, bool changed, |
227 | bool emitSignal) |
228 | { |
229 | if(position >= 0 && uInt32(position) < _valueList.size()) |
230 | { |
231 | // Correctly format the data for viewing |
232 | editString() = Common::Base::toString(value, _base); |
233 | |
234 | _valueStringList[position] = editString(); |
235 | _changedList[position] = changed; |
236 | _valueList[position] = value; |
237 | |
238 | if(emitSignal) |
239 | sendCommand(DataGridWidget::kItemDataChangedCmd, position, _id); |
240 | |
241 | setDirty(); |
242 | } |
243 | } |
244 | |
245 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
246 | void DataGridWidget::setRange(int lower, int upper) |
247 | { |
248 | _lowerBound = std::max(0, lower); |
249 | _upperBound = std::min(1 << _bits, upper); |
250 | } |
251 | |
252 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
253 | void DataGridWidget::handleMouseEntered() |
254 | { |
255 | setFlags(Widget::FLAG_HILITED); |
256 | setDirty(); |
257 | } |
258 | |
259 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
260 | void DataGridWidget::handleMouseLeft() |
261 | { |
262 | clearFlags(Widget::FLAG_HILITED); |
263 | setDirty(); |
264 | } |
265 | |
266 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
267 | void DataGridWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) |
268 | { |
269 | if (!isEnabled()) |
270 | return; |
271 | |
272 | // First check whether the selection changed |
273 | int newSelectedItem; |
274 | newSelectedItem = findItem(x, y); |
275 | if (newSelectedItem > int(_valueList.size()) - 1) |
276 | newSelectedItem = -1; |
277 | |
278 | if (_selectedItem != newSelectedItem) |
279 | { |
280 | if (_editMode) |
281 | abortEditMode(); |
282 | |
283 | _selectedItem = newSelectedItem; |
284 | _currentRow = _selectedItem / _cols; |
285 | _currentCol = _selectedItem - (_currentRow * _cols); |
286 | |
287 | sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); |
288 | setDirty(); |
289 | } |
290 | } |
291 | |
292 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
293 | void DataGridWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) |
294 | { |
295 | // If this was a double click and the mouse is still over the selected item, |
296 | // send the double click command |
297 | if (clickCount == 2 && (_selectedItem == findItem(x, y))) |
298 | { |
299 | sendCommand(DataGridWidget::kItemDoubleClickedCmd, _selectedItem, _id); |
300 | |
301 | // Start edit mode |
302 | if(isEditable() && !_editMode) |
303 | startEditMode(); |
304 | } |
305 | } |
306 | |
307 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
308 | void DataGridWidget::handleMouseWheel(int x, int y, int direction) |
309 | { |
310 | if(_scrollBar) |
311 | _scrollBar->handleMouseWheel(x, y, direction); |
312 | else if(isEditable()) |
313 | { |
314 | if(direction > 0) |
315 | decrementCell(); |
316 | else if(direction < 0) |
317 | incrementCell(); |
318 | } |
319 | } |
320 | |
321 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
322 | int DataGridWidget::findItem(int x, int y) |
323 | { |
324 | int row = (y - 1) / _rowHeight; |
325 | if(row >= _rows) row = _rows - 1; |
326 | |
327 | int col = x / _colWidth; |
328 | if(col >= _cols) col = _cols - 1; |
329 | |
330 | return row * _cols + col; |
331 | } |
332 | |
333 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
334 | bool DataGridWidget::handleText(char text) |
335 | { |
336 | if(_editMode) |
337 | { |
338 | // Class EditableWidget handles all text editing related key presses for us |
339 | return EditableWidget::handleText(text); |
340 | } |
341 | return false; |
342 | } |
343 | |
344 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
345 | bool DataGridWidget::handleKeyDown(StellaKey key, StellaMod mod) |
346 | { |
347 | // Ignore all mod keys |
348 | if(StellaModTest::isControl(mod) || StellaModTest::isAlt(mod)) |
349 | return true; |
350 | |
351 | bool handled = true; |
352 | bool dirty = false; |
353 | |
354 | if (_editMode) |
355 | { |
356 | // Class EditableWidget handles all single-key presses for us |
357 | handled = EditableWidget::handleKeyDown(key, mod); |
358 | } |
359 | else |
360 | { |
361 | switch(key) |
362 | { |
363 | case KBDK_RETURN: |
364 | case KBDK_KP_ENTER: |
365 | if (_currentRow >= 0 && _currentCol >= 0) |
366 | { |
367 | dirty = true; |
368 | _selectedItem = _currentRow*_cols + _currentCol; |
369 | startEditMode(); |
370 | } |
371 | break; |
372 | |
373 | case KBDK_UP: |
374 | if (_currentRow > 0) |
375 | { |
376 | _currentRow--; |
377 | dirty = true; |
378 | } |
379 | else if(_currentCol > 0) |
380 | { |
381 | _currentRow = _rows - 1; |
382 | _currentCol--; |
383 | dirty = true; |
384 | } |
385 | break; |
386 | |
387 | case KBDK_DOWN: |
388 | if (_currentRow < int(_rows) - 1) |
389 | { |
390 | _currentRow++; |
391 | dirty = true; |
392 | } |
393 | else if(_currentCol < int(_cols) - 1) |
394 | { |
395 | _currentRow = 0; |
396 | _currentCol++; |
397 | dirty = true; |
398 | } |
399 | break; |
400 | |
401 | case KBDK_LEFT: |
402 | if (_currentCol > 0) |
403 | { |
404 | _currentCol--; |
405 | dirty = true; |
406 | } |
407 | else if(_currentRow > 0) |
408 | { |
409 | _currentCol = _cols - 1; |
410 | _currentRow--; |
411 | dirty = true; |
412 | } |
413 | break; |
414 | |
415 | case KBDK_RIGHT: |
416 | if (_currentCol < int(_cols) - 1) |
417 | { |
418 | _currentCol++; |
419 | dirty = true; |
420 | } |
421 | else if(_currentRow < int(_rows) - 1) |
422 | { |
423 | _currentCol = 0; |
424 | _currentRow++; |
425 | dirty = true; |
426 | } |
427 | break; |
428 | |
429 | case KBDK_PAGEUP: |
430 | if(StellaModTest::isShift(mod) && _scrollBar) |
431 | handleMouseWheel(0, 0, -1); |
432 | else if (_currentRow > 0) |
433 | { |
434 | _currentRow = 0; |
435 | dirty = true; |
436 | } |
437 | break; |
438 | |
439 | case KBDK_PAGEDOWN: |
440 | if(StellaModTest::isShift(mod) && _scrollBar) |
441 | handleMouseWheel(0, 0, +1); |
442 | else if (_currentRow < int(_rows) - 1) |
443 | { |
444 | _currentRow = _rows - 1; |
445 | dirty = true; |
446 | } |
447 | break; |
448 | |
449 | case KBDK_HOME: |
450 | if (_currentCol > 0) |
451 | { |
452 | _currentCol = 0; |
453 | dirty = true; |
454 | } |
455 | break; |
456 | |
457 | case KBDK_END: |
458 | if (_currentCol < int(_cols) - 1) |
459 | { |
460 | _currentCol = _cols - 1; |
461 | dirty = true; |
462 | } |
463 | break; |
464 | |
465 | case KBDK_N: // negate |
466 | if(isEditable()) |
467 | negateCell(); |
468 | break; |
469 | |
470 | case KBDK_I: // invert |
471 | if(isEditable()) |
472 | invertCell(); |
473 | break; |
474 | |
475 | case KBDK_MINUS: // decrement |
476 | case KBDK_KP_MINUS: |
477 | if(isEditable()) |
478 | decrementCell(); |
479 | break; |
480 | |
481 | case KBDK_EQUALS: // increment |
482 | case KBDK_KP_PLUS: |
483 | if(isEditable()) |
484 | incrementCell(); |
485 | break; |
486 | |
487 | case KBDK_COMMA: // shift left |
488 | if(isEditable()) |
489 | lshiftCell(); |
490 | break; |
491 | |
492 | case KBDK_PERIOD: // shift right |
493 | if(isEditable()) |
494 | rshiftCell(); |
495 | break; |
496 | |
497 | case KBDK_Z: // zero |
498 | if(isEditable()) |
499 | zeroCell(); |
500 | break; |
501 | |
502 | default: |
503 | handled = false; |
504 | } |
505 | } |
506 | |
507 | if (dirty) |
508 | { |
509 | int oldItem = _selectedItem; |
510 | _selectedItem = _currentRow*_cols + _currentCol; |
511 | |
512 | if(_selectedItem != oldItem) |
513 | sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); |
514 | |
515 | setDirty(); |
516 | } |
517 | |
518 | _currentKeyDown = key; |
519 | return handled; |
520 | } |
521 | |
522 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
523 | bool DataGridWidget::handleKeyUp(StellaKey key, StellaMod mod) |
524 | { |
525 | if (key == _currentKeyDown) |
526 | _currentKeyDown = KBDK_UNKNOWN; |
527 | return true; |
528 | } |
529 | |
530 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
531 | void DataGridWidget::receivedFocusWidget() |
532 | { |
533 | // Enable the operations widget and make it send its signals here |
534 | if(_opsWidget) |
535 | { |
536 | _opsWidget->setEnabled(true); |
537 | _opsWidget->setTarget(this); |
538 | } |
539 | } |
540 | |
541 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
542 | void DataGridWidget::lostFocusWidget() |
543 | { |
544 | enableEditMode(false); |
545 | |
546 | // Disable the operations widget |
547 | if(_opsWidget) |
548 | _opsWidget->setEnabled(false); |
549 | } |
550 | |
551 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
552 | void DataGridWidget::handleCommand(CommandSender* sender, int cmd, |
553 | int data, int id) |
554 | { |
555 | switch(cmd) |
556 | { |
557 | case GuiObject::kSetPositionCmd: |
558 | // Chain access; pass to parent |
559 | sendCommand(GuiObject::kSetPositionCmd, data, _id); |
560 | break; |
561 | |
562 | case kDGZeroCmd: |
563 | zeroCell(); |
564 | break; |
565 | |
566 | case kDGInvertCmd: |
567 | invertCell(); |
568 | break; |
569 | |
570 | case kDGNegateCmd: |
571 | negateCell(); |
572 | break; |
573 | |
574 | case kDGIncCmd: |
575 | incrementCell(); |
576 | break; |
577 | |
578 | case kDGDecCmd: |
579 | decrementCell(); |
580 | break; |
581 | |
582 | case kDGShiftLCmd: |
583 | lshiftCell(); |
584 | break; |
585 | |
586 | case kDGShiftRCmd: |
587 | rshiftCell(); |
588 | break; |
589 | } |
590 | } |
591 | |
592 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
593 | void DataGridWidget::drawWidget(bool hilite) |
594 | { |
595 | FBSurface& s = _boss->dialog().surface(); |
596 | bool onTop = _boss->dialog().isOnTop(); |
597 | int row, col; |
598 | |
599 | s.fillRect(_x, _y, _w, _h, hilite && isEnabled() && isEditable() ? _bgcolorhi : onTop ? _bgcolor : kBGColorHi); |
600 | // Draw the internal grid and labels |
601 | int linewidth = _cols * _colWidth; |
602 | s.frameRect(_x, _y, _w, _h, hilite && isEnabled() && isEditable() ? kWidColorHi : kColor); |
603 | for(row = 1; row <= _rows-1; row++) |
604 | s.hLine(_x+1, _y + (row * _rowHeight), _x + linewidth-1, kBGColorLo); |
605 | |
606 | int lineheight = _rows * _rowHeight; |
607 | for(col = 1; col <= _cols-1; col++) |
608 | s.vLine(_x + (col * _colWidth), _y+1, _y + lineheight-1, kBGColorLo); |
609 | |
610 | // Draw the list items |
611 | for (row = 0; row < _rows; row++) |
612 | { |
613 | for (col = 0; col < _cols; col++) |
614 | { |
615 | int x = _x + 4 + (col * _colWidth); |
616 | int y = _y + 2 + (row * _rowHeight); |
617 | int pos = row*_cols + col; |
618 | ColorId textColor = onTop ? kTextColor : kColor; |
619 | |
620 | // Draw the selected item inverted, on a highlighted background. |
621 | if (_currentRow == row && _currentCol == col && |
622 | _hasFocus && !_editMode) |
623 | { |
624 | s.fillRect(x - 4, y - 2, _colWidth+1, _rowHeight+1, kTextColorHi); |
625 | textColor = kTextColorInv; |
626 | } |
627 | |
628 | if (_selectedItem == pos && _editMode) |
629 | { |
630 | adjustOffset(); |
631 | s.drawString(_font, editString(), x, y, _colWidth, textColor, |
632 | TextAlign::Left, -_editScrollOffset, false); |
633 | } |
634 | else |
635 | { |
636 | if(_changedList[pos]) |
637 | { |
638 | s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, |
639 | onTop ? kDbgChangedColor : _bgcolorlo); |
640 | |
641 | if(_hiliteList[pos]) |
642 | textColor = kDbgColorHi; |
643 | else |
644 | textColor = onTop ? kDbgChangedTextColor : textColor; |
645 | } |
646 | else if(_hiliteList[pos]) |
647 | textColor = kDbgColorHi; |
648 | |
649 | s.drawString(_font, _valueStringList[pos], x, y, _colWidth, textColor); |
650 | } |
651 | } |
652 | } |
653 | |
654 | // Only draw the caret while editing, and if it's in the current viewport |
655 | if(_editMode) |
656 | drawCaret(); |
657 | |
658 | // Draw the scrollbar |
659 | if(_scrollBar) |
660 | _scrollBar->recalc(); // takes care of the draw |
661 | |
662 | // Cross out the grid? |
663 | if(_crossGrid) |
664 | { |
665 | s.line(_x + 1, _y + 1, _x + _w - 2, _y + _h - 1, kColor); |
666 | s.line(_x + _w - 2, _y + 1, _x + 1, _y + _h - 1, kColor); |
667 | } |
668 | } |
669 | |
670 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
671 | Common::Rect DataGridWidget::getEditRect() const |
672 | { |
673 | const int rowoffset = _currentRow * _rowHeight; |
674 | const int coloffset = _currentCol * _colWidth + 4; |
675 | |
676 | return Common::Rect(1 + coloffset, rowoffset, |
677 | _colWidth + coloffset - 5, _rowHeight + rowoffset); |
678 | } |
679 | |
680 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
681 | int DataGridWidget::getWidth() const |
682 | { |
683 | return _w + (_scrollBar ? kScrollBarWidth : 0); |
684 | } |
685 | |
686 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
687 | void DataGridWidget::startEditMode() |
688 | { |
689 | if (isEditable() && !_editMode && _selectedItem >= 0) |
690 | { |
691 | enableEditMode(true); |
692 | setText("" , true); // Erase current entry when starting editing |
693 | } |
694 | } |
695 | |
696 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
697 | void DataGridWidget::endEditMode() |
698 | { |
699 | if (!_editMode) |
700 | return; |
701 | |
702 | enableEditMode(false); |
703 | |
704 | // Update the both the string representation and the real data |
705 | if(editString().size() > 0 && !(editString()[0] == '$' || |
706 | editString()[0] == '#' || editString()[0] == '\\')) |
707 | { |
708 | switch(_base) |
709 | { |
710 | case Common::Base::F_16: |
711 | case Common::Base::F_16_1: |
712 | case Common::Base::F_16_2: |
713 | case Common::Base::F_16_4: |
714 | case Common::Base::F_16_8: |
715 | editString().insert(0, 1, '$'); |
716 | break; |
717 | case Common::Base::F_2: |
718 | case Common::Base::F_2_8: |
719 | case Common::Base::F_2_16: |
720 | editString().insert(0, 1, '\\'); |
721 | break; |
722 | case Common::Base::F_10: |
723 | editString().insert(0, 1, '#'); |
724 | break; |
725 | case Common::Base::F_DEFAULT: |
726 | default: // TODO - properly handle all other cases |
727 | break; |
728 | } |
729 | } |
730 | int value = instance().debugger().stringToValue(editString()); |
731 | if(value < _lowerBound || value >= _upperBound) |
732 | { |
733 | abortEditMode(); |
734 | return; |
735 | } |
736 | |
737 | setSelectedValue(value); |
738 | } |
739 | |
740 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
741 | void DataGridWidget::abortEditMode() |
742 | { |
743 | if(_editMode) |
744 | { |
745 | // Undo any changes made |
746 | assert(_selectedItem >= 0); |
747 | enableEditMode(false); |
748 | } |
749 | } |
750 | |
751 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
752 | void DataGridWidget::negateCell() |
753 | { |
754 | int mask = (1 << _bits) - 1; |
755 | int value = getSelectedValue(); |
756 | if(mask != _upperBound - 1) // ignore when values aren't byte-aligned |
757 | return; |
758 | |
759 | value = ((~value) + 1) & mask; |
760 | setSelectedValue(value); |
761 | } |
762 | |
763 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
764 | void DataGridWidget::invertCell() |
765 | { |
766 | int mask = (1 << _bits) - 1; |
767 | int value = getSelectedValue(); |
768 | if(mask != _upperBound - 1) // ignore when values aren't byte-aligned |
769 | return; |
770 | |
771 | value = ~value & mask; |
772 | setSelectedValue(value); |
773 | } |
774 | |
775 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
776 | void DataGridWidget::decrementCell() |
777 | { |
778 | int mask = (1 << _bits) - 1; |
779 | int value = getSelectedValue(); |
780 | if(value <= _lowerBound) // take care of wrap-around |
781 | value = _upperBound; |
782 | |
783 | value = (value - 1) & mask; |
784 | setSelectedValue(value); |
785 | } |
786 | |
787 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
788 | void DataGridWidget::incrementCell() |
789 | { |
790 | int mask = (1 << _bits) - 1; |
791 | int value = getSelectedValue(); |
792 | if(value >= _upperBound - 1) // take care of wrap-around |
793 | value = _lowerBound - 1; |
794 | |
795 | value = (value + 1) & mask; |
796 | setSelectedValue(value); |
797 | } |
798 | |
799 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
800 | void DataGridWidget::lshiftCell() |
801 | { |
802 | int mask = (1 << _bits) - 1; |
803 | int value = getSelectedValue(); |
804 | if(mask != _upperBound - 1) // ignore when values aren't byte-aligned |
805 | return; |
806 | |
807 | value = (value << 1) & mask; |
808 | setSelectedValue(value); |
809 | } |
810 | |
811 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
812 | void DataGridWidget::rshiftCell() |
813 | { |
814 | int mask = (1 << _bits) - 1; |
815 | int value = getSelectedValue(); |
816 | if(mask != _upperBound - 1) // ignore when values aren't byte-aligned |
817 | return; |
818 | |
819 | value = (value >> 1) & mask; |
820 | setSelectedValue(value); |
821 | } |
822 | |
823 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
824 | void DataGridWidget::zeroCell() |
825 | { |
826 | setSelectedValue(0); |
827 | } |
828 | |