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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31DataGridWidget::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
115void DataGridWidget::setList(const IntArray& alist, const IntArray& vlist,
116 const BoolArray& changed)
117{
118/*
119cerr << "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/*
142cerr << "_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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
157void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
170void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
184void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
201void DataGridWidget::setNumRows(int rows)
202{
203 if(_scrollBar)
204 _scrollBar->_numEntries = rows;
205}
206
207// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
208void DataGridWidget::setSelectedValue(int value)
209{
210 setValue(_selectedItem, value, _valueList[_selectedItem] != value);
211}
212
213// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
214void DataGridWidget::setValue(int position, int value)
215{
216 setValue(position, value, _valueList[position] != value);
217}
218
219// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
220void DataGridWidget::setValueInternal(int position, int value, bool changed)
221{
222 setValue(position, value, changed, false);
223}
224
225// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
226void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246void DataGridWidget::setRange(int lower, int upper)
247{
248 _lowerBound = std::max(0, lower);
249 _upperBound = std::min(1 << _bits, upper);
250}
251
252// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
253void DataGridWidget::handleMouseEntered()
254{
255 setFlags(Widget::FLAG_HILITED);
256 setDirty();
257}
258
259// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
260void DataGridWidget::handleMouseLeft()
261{
262 clearFlags(Widget::FLAG_HILITED);
263 setDirty();
264}
265
266// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
267void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
293void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
308void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
322int 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
334bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
345bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
523bool DataGridWidget::handleKeyUp(StellaKey key, StellaMod mod)
524{
525 if (key == _currentKeyDown)
526 _currentKeyDown = KBDK_UNKNOWN;
527 return true;
528}
529
530// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
531void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
542void DataGridWidget::lostFocusWidget()
543{
544 enableEditMode(false);
545
546 // Disable the operations widget
547 if(_opsWidget)
548 _opsWidget->setEnabled(false);
549}
550
551// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
552void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
593void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
671Common::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
681int DataGridWidget::getWidth() const
682{
683 return _w + (_scrollBar ? kScrollBarWidth : 0);
684}
685
686// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
687void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
697void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
741void DataGridWidget::abortEditMode()
742{
743 if(_editMode)
744 {
745 // Undo any changes made
746 assert(_selectedItem >= 0);
747 enableEditMode(false);
748 }
749}
750
751// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
752void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
764void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
776void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
788void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
800void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
812void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
824void DataGridWidget::zeroCell()
825{
826 setSelectedValue(0);
827}
828