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 "bspf.hxx" |
19 | #include "Debugger.hxx" |
20 | #include "DiStella.hxx" |
21 | #include "Widget.hxx" |
22 | #include "StellaKeys.hxx" |
23 | #include "FBSurface.hxx" |
24 | #include "Font.hxx" |
25 | #include "ScrollBarWidget.hxx" |
26 | #include "RomListSettings.hxx" |
27 | #include "RomListWidget.hxx" |
28 | |
29 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
30 | RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont, |
31 | const GUI::Font& nfont, |
32 | int x, int y, int w, int h) |
33 | : EditableWidget(boss, nfont, x, y, 16, 16), |
34 | _rows(0), |
35 | _cols(0), |
36 | _currentPos(0), |
37 | _selectedItem(-1), |
38 | _highlightedItem(-1), |
39 | _editMode(false), |
40 | _currentKeyDown(KBDK_UNKNOWN), |
41 | _base(Common::Base::F_DEFAULT), |
42 | myDisasm(nullptr)//, |
43 | { |
44 | _flags = Widget::FLAG_ENABLED | Widget::FLAG_CLEARBG | Widget::FLAG_RETAIN_FOCUS; |
45 | _bgcolor = kWidColor; |
46 | _bgcolorhi = kWidColor; |
47 | _textcolor = kTextColor; |
48 | _textcolorhi = kTextColor; |
49 | |
50 | _cols = w / _fontWidth; |
51 | _rows = h / _fontHeight; |
52 | |
53 | // Set real dimensions |
54 | _w = w - kScrollBarWidth; |
55 | _h = h + 2; |
56 | |
57 | // Create scrollbar and attach to the list |
58 | myScrollBar = new ScrollBarWidget(boss, lfont, _x + _w, _y, kScrollBarWidth, _h); |
59 | myScrollBar->setTarget(this); |
60 | |
61 | // Add settings menu |
62 | myMenu = make_unique<RomListSettings>(this, lfont); |
63 | |
64 | // Take advantage of a wide debugger window when possible |
65 | const int fontWidth = lfont.getMaxCharWidth(), |
66 | numchars = w / fontWidth; |
67 | |
68 | _labelWidth = std::max(14, int(0.45 * (numchars - 8 - 8 - 9 - 2))) * fontWidth - 1; |
69 | _bytesWidth = 9 * fontWidth; |
70 | |
71 | /////////////////////////////////////////////////////// |
72 | // Add checkboxes |
73 | int ypos = _y + 2; |
74 | |
75 | // rowheight is determined by largest item on a line, |
76 | // possibly meaning that number of rows will change |
77 | _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize()); |
78 | _rows = h / _fontHeight; |
79 | |
80 | // Create a CheckboxWidget for each row in the list |
81 | for(int i = 0; i < _rows; ++i) |
82 | { |
83 | CheckboxWidget* t = new CheckboxWidget(boss, lfont, _x + 2, ypos, "" , |
84 | CheckboxWidget::kCheckActionCmd); |
85 | t->setTarget(this); |
86 | t->setID(i); |
87 | t->setFill(CheckboxWidget::FillType::Circle); |
88 | t->setTextColor(kTextColorEm); |
89 | ypos += _fontHeight; |
90 | |
91 | myCheckList.push_back(t); |
92 | } |
93 | |
94 | // Add filtering |
95 | EditableWidget::TextFilter f = [&](char c) |
96 | { |
97 | switch(_base) |
98 | { |
99 | case Common::Base::F_16: |
100 | case Common::Base::F_16_1: |
101 | case Common::Base::F_16_2: |
102 | case Common::Base::F_16_4: |
103 | case Common::Base::F_16_8: |
104 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == ' '; |
105 | |
106 | case Common::Base::F_2: |
107 | case Common::Base::F_2_8: |
108 | case Common::Base::F_2_16: |
109 | return c == '0' || c == '1' || c == ' '; |
110 | |
111 | case Common::Base::F_10: |
112 | return (c >= '0' && c <= '9') || c == ' '; |
113 | |
114 | case Common::Base::F_DEFAULT: |
115 | default: // TODO - properly handle all other cases |
116 | return false; |
117 | } |
118 | }; |
119 | setTextFilter(f); |
120 | } |
121 | |
122 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
123 | void RomListWidget::setList(const CartDebug::Disassembly& disasm) |
124 | { |
125 | myDisasm = &disasm; |
126 | |
127 | // Enable all checkboxes |
128 | for(int i = 0; i < _rows; ++i) |
129 | myCheckList[i]->setFlags(Widget::FLAG_ENABLED); |
130 | |
131 | // Then turn off any extras |
132 | if(int(myDisasm->list.size()) < _rows) |
133 | for(int i = int(myDisasm->list.size()); i < _rows; ++i) |
134 | myCheckList[i]->clearFlags(Widget::FLAG_ENABLED); |
135 | |
136 | recalc(); |
137 | } |
138 | |
139 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
140 | void RomListWidget::setSelected(int item) |
141 | { |
142 | if(item < -1 || item >= int(myDisasm->list.size())) |
143 | return; |
144 | |
145 | if(isEnabled()) |
146 | { |
147 | if(_editMode) |
148 | abortEditMode(); |
149 | |
150 | _currentPos = _selectedItem = item; |
151 | scrollToSelected(); |
152 | } |
153 | } |
154 | |
155 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
156 | void RomListWidget::setHighlighted(int item) |
157 | { |
158 | if(item < -1 || item >= int(myDisasm->list.size())) |
159 | return; |
160 | |
161 | if(isEnabled()) |
162 | { |
163 | if(_editMode) |
164 | abortEditMode(); |
165 | |
166 | _highlightedItem = item; |
167 | |
168 | // Only scroll the list if we're about to pass the page boundary |
169 | if (_highlightedItem < _currentPos) |
170 | { |
171 | _currentPos -= _rows; |
172 | if (_currentPos < 0) |
173 | _currentPos = 0; |
174 | } |
175 | else if(_highlightedItem == _currentPos + _rows) |
176 | _currentPos += _rows; |
177 | |
178 | scrollToHighlighted(); |
179 | } |
180 | } |
181 | |
182 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
183 | int RomListWidget::findItem(int x, int y) const |
184 | { |
185 | return (y - 1) / _fontHeight + _currentPos; |
186 | } |
187 | |
188 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
189 | void RomListWidget::recalc() |
190 | { |
191 | int size = int(myDisasm->list.size()); |
192 | |
193 | if (_currentPos >= size) |
194 | _currentPos = size - 1; |
195 | if (_currentPos < 0) |
196 | _currentPos = 0; |
197 | |
198 | if(_selectedItem < 0 || _selectedItem >= size) |
199 | _selectedItem = 0; |
200 | |
201 | _editMode = false; |
202 | |
203 | myScrollBar->_numEntries = int(myDisasm->list.size()); |
204 | myScrollBar->_entriesPerPage = _rows; |
205 | |
206 | // Reset to normal data entry |
207 | abortEditMode(); |
208 | |
209 | setDirty(); |
210 | } |
211 | |
212 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
213 | void RomListWidget::scrollToCurrent(int item) |
214 | { |
215 | // Only do something if the current item is not in our view port |
216 | if (item < _currentPos) |
217 | { |
218 | // it's above our view |
219 | _currentPos = item; |
220 | } |
221 | else if (item >= _currentPos + _rows ) |
222 | { |
223 | // it's below our view |
224 | _currentPos = item - _rows + 1; |
225 | } |
226 | |
227 | int size = int(myDisasm->list.size()); |
228 | if (_currentPos < 0 || _rows > size) |
229 | _currentPos = 0; |
230 | else if (_currentPos + _rows > size) |
231 | _currentPos = size - _rows; |
232 | |
233 | myScrollBar->_currentPos = _currentPos; |
234 | myScrollBar->recalc(); |
235 | |
236 | setDirty(); |
237 | } |
238 | |
239 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
240 | void RomListWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) |
241 | { |
242 | if (!isEnabled()) |
243 | return; |
244 | |
245 | // Grab right mouse button for context menu, left for selection/edit mode |
246 | if(b == MouseButton::RIGHT) |
247 | { |
248 | // Set selected and add menu at current x,y mouse location |
249 | _selectedItem = findItem(x, y); |
250 | scrollToSelected(); |
251 | myMenu->show(x + getAbsX(), y + getAbsY(), |
252 | dialog().surface().dstRect(), _selectedItem); |
253 | } |
254 | else |
255 | { |
256 | // First check whether the selection changed |
257 | int newSelectedItem; |
258 | newSelectedItem = findItem(x, y); |
259 | if (newSelectedItem > int(myDisasm->list.size()) - 1) |
260 | newSelectedItem = -1; |
261 | |
262 | if (_selectedItem != newSelectedItem) |
263 | { |
264 | if (_editMode) |
265 | abortEditMode(); |
266 | _selectedItem = newSelectedItem; |
267 | setDirty(); |
268 | } |
269 | } |
270 | } |
271 | |
272 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
273 | void RomListWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) |
274 | { |
275 | // If this was a double click and the mouse is still over the selected item, |
276 | // send the double click command |
277 | if (clickCount == 2 && (_selectedItem == findItem(x, y))) |
278 | { |
279 | // Start edit mode |
280 | if(isEditable() && !_editMode) |
281 | startEditMode(); |
282 | } |
283 | } |
284 | |
285 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
286 | void RomListWidget::handleMouseWheel(int x, int y, int direction) |
287 | { |
288 | myScrollBar->handleMouseWheel(x, y, direction); |
289 | } |
290 | |
291 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
292 | void RomListWidget::handleMouseEntered() |
293 | { |
294 | setFlags(Widget::FLAG_HILITED); |
295 | setDirty(); |
296 | } |
297 | |
298 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
299 | void RomListWidget::handleMouseLeft() |
300 | { |
301 | clearFlags(Widget::FLAG_HILITED); |
302 | setDirty(); |
303 | } |
304 | |
305 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
306 | bool RomListWidget::handleText(char text) |
307 | { |
308 | if(_editMode) |
309 | { |
310 | // Class EditableWidget handles all text editing related key presses for us |
311 | return EditableWidget::handleText(text); |
312 | } |
313 | return false; |
314 | } |
315 | |
316 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
317 | bool RomListWidget::handleKeyDown(StellaKey key, StellaMod mod) |
318 | { |
319 | // Ignore all Alt-mod keys |
320 | if(StellaModTest::isAlt(mod)) |
321 | return true; |
322 | |
323 | bool handled = true; |
324 | int oldSelectedItem = _selectedItem; |
325 | |
326 | if (_editMode) |
327 | { |
328 | // Class EditableWidget handles all single-key presses for us |
329 | handled = EditableWidget::handleKeyDown(key, mod); |
330 | } |
331 | else |
332 | { |
333 | switch (key) |
334 | { |
335 | case KBDK_SPACE: |
336 | // Snap list back to currently highlighted line |
337 | if(_highlightedItem >= 0) |
338 | { |
339 | _currentPos = _highlightedItem; |
340 | scrollToHighlighted(); |
341 | } |
342 | break; |
343 | |
344 | default: |
345 | handled = false; |
346 | } |
347 | } |
348 | |
349 | if (_selectedItem != oldSelectedItem) |
350 | { |
351 | myScrollBar->draw(); |
352 | scrollToSelected(); |
353 | } |
354 | |
355 | _currentKeyDown = key; |
356 | return handled; |
357 | } |
358 | |
359 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
360 | bool RomListWidget::handleKeyUp(StellaKey key, StellaMod mod) |
361 | { |
362 | if (key == _currentKeyDown) |
363 | _currentKeyDown = KBDK_UNKNOWN; |
364 | return true; |
365 | } |
366 | |
367 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
368 | bool RomListWidget::handleEvent(Event::Type e) |
369 | { |
370 | if(!isEnabled() || _editMode) |
371 | return false; |
372 | |
373 | bool handled = true; |
374 | int oldSelectedItem = _selectedItem; |
375 | |
376 | switch(e) |
377 | { |
378 | case Event::UISelect: |
379 | if (_selectedItem >= 0) |
380 | { |
381 | if (isEditable()) |
382 | startEditMode(); |
383 | } |
384 | break; |
385 | |
386 | case Event::UIUp: |
387 | if (_selectedItem > 0) |
388 | _selectedItem--; |
389 | break; |
390 | |
391 | case Event::UIDown: |
392 | if (_selectedItem < int(myDisasm->list.size()) - 1) |
393 | _selectedItem++; |
394 | break; |
395 | |
396 | case Event::UIPgUp: |
397 | _selectedItem -= _rows - 1; |
398 | if (_selectedItem < 0) |
399 | _selectedItem = 0; |
400 | break; |
401 | |
402 | case Event::UIPgDown: |
403 | _selectedItem += _rows - 1; |
404 | if (_selectedItem >= int(myDisasm->list.size())) |
405 | _selectedItem = int(myDisasm->list.size()) - 1; |
406 | break; |
407 | |
408 | case Event::UIHome: |
409 | _selectedItem = 0; |
410 | break; |
411 | |
412 | case Event::UIEnd: |
413 | _selectedItem = int(myDisasm->list.size()) - 1; |
414 | break; |
415 | |
416 | default: |
417 | handled = false; |
418 | } |
419 | |
420 | if (_selectedItem != oldSelectedItem) |
421 | { |
422 | myScrollBar->draw(); |
423 | scrollToSelected(); |
424 | } |
425 | |
426 | return handled; |
427 | } |
428 | |
429 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
430 | void RomListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) |
431 | { |
432 | switch (cmd) |
433 | { |
434 | case CheckboxWidget::kCheckActionCmd: |
435 | // We let the parent class handle this |
436 | // Pass it as a kRLBreakpointChangedCmd command, since that's the intent |
437 | sendCommand(RomListWidget::kBPointChangedCmd, _currentPos+id, 0); |
438 | break; |
439 | |
440 | case GuiObject::kSetPositionCmd: |
441 | if (_currentPos != data) |
442 | { |
443 | _currentPos = data; |
444 | setDirty(); |
445 | } |
446 | break; |
447 | |
448 | default: |
449 | // Let the parent class handle all other commands directly |
450 | sendCommand(cmd, data, id); |
451 | } |
452 | } |
453 | |
454 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
455 | void RomListWidget::lostFocusWidget() |
456 | { |
457 | _editMode = false; |
458 | |
459 | // Reset to normal data entry |
460 | abortEditMode(); |
461 | } |
462 | |
463 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
464 | void RomListWidget::drawWidget(bool hilite) |
465 | { |
466 | FBSurface& s = _boss->dialog().surface(); |
467 | bool onTop = _boss->dialog().isOnTop(); |
468 | const CartDebug::DisassemblyList& dlist = myDisasm->list; |
469 | int i, pos, xpos, ypos, len = int(dlist.size()); |
470 | ColorId textColor = onTop ? kTextColor : kColor; |
471 | |
472 | const Common::Rect& r = getEditRect(); |
473 | const Common::Rect& l = getLineRect(); |
474 | |
475 | // Draw a thin frame around the list and to separate columns |
476 | s.frameRect(_x, _y, _w + 1, _h, hilite ? kWidColorHi : kColor); |
477 | s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor); |
478 | |
479 | // Draw the list items |
480 | int cycleCountW = _fontWidth * 8, |
481 | noTypeDisasmW = _w - l.x() - _labelWidth, |
482 | noCodeDisasmW = noTypeDisasmW - r.w(), |
483 | codeDisasmW = noCodeDisasmW - cycleCountW, |
484 | actualWidth = myDisasm->fieldwidth * _fontWidth; |
485 | if(actualWidth < codeDisasmW) |
486 | codeDisasmW = actualWidth; |
487 | |
488 | xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2; |
489 | for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight) |
490 | { |
491 | ColorId bytesColor = textColor; |
492 | |
493 | // Draw checkboxes for correct lines (takes scrolling into account) |
494 | myCheckList[i]->setState(instance().debugger(). |
495 | checkBreakPoint(dlist[pos].address, |
496 | instance().debugger().cartDebug().getBank(dlist[pos].address))); |
497 | |
498 | myCheckList[i]->setDirty(); |
499 | myCheckList[i]->draw(); |
500 | |
501 | // Draw highlighted item in a frame |
502 | if (_highlightedItem == pos) |
503 | s.frameRect(_x + l.x() - 3, ypos - 1, _w - l.x(), _fontHeight, onTop ? kWidColorHi : kBGColorLo); |
504 | |
505 | // Draw the selected item inverted, on a highlighted background. |
506 | if(_selectedItem == pos && _hasFocus) |
507 | { |
508 | if(!_editMode) |
509 | { |
510 | s.fillRect(_x + r.x() - 3, ypos - 1, r.w(), _fontHeight, kTextColorHi); |
511 | bytesColor = kTextColorInv; |
512 | } |
513 | else |
514 | s.frameRect(_x + r.x() - 3, ypos - 1, r.w(), _fontHeight, kWidColorHi); |
515 | } |
516 | |
517 | // Draw labels |
518 | s.drawString(_font, dlist[pos].label, xpos, ypos, _labelWidth, |
519 | dlist[pos].hllabel ? textColor : kColor); |
520 | |
521 | // Bytes are only editable if they represent code, graphics, or accessible data |
522 | // Otherwise, the disassembly should get all remaining space |
523 | if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX|CartDebug::DATA)) |
524 | { |
525 | if(dlist[pos].type == CartDebug::CODE) |
526 | { |
527 | // Draw mnemonic |
528 | s.drawString(_font, dlist[pos].disasm.substr(0, 7), xpos + _labelWidth, ypos, |
529 | 7 * _fontWidth, textColor); |
530 | // Draw operand |
531 | if (dlist[pos].disasm.length() > 8) |
532 | s.drawString(_font, dlist[pos].disasm.substr(8), xpos + _labelWidth + 7 * _fontWidth, ypos, |
533 | codeDisasmW - 7 * _fontWidth, textColor); |
534 | // Draw cycle count |
535 | s.drawString(_font, dlist[pos].ccount, xpos + _labelWidth + codeDisasmW, ypos, |
536 | cycleCountW, textColor); |
537 | } |
538 | else |
539 | { |
540 | // Draw disassembly only |
541 | s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, |
542 | noCodeDisasmW - 4, kTextColor); |
543 | } |
544 | |
545 | // Draw separator |
546 | s.vLine(_x + r.x() - 7, ypos, ypos + _fontHeight - 1, kColor); |
547 | |
548 | // Draw bytes |
549 | { |
550 | if (_selectedItem == pos && _editMode) |
551 | { |
552 | adjustOffset(); |
553 | s.drawString(_font, editString(), _x + r.x(), ypos, r.w(), textColor, |
554 | TextAlign::Left, -_editScrollOffset, false); |
555 | |
556 | drawCaret(); |
557 | } |
558 | else |
559 | { |
560 | s.drawString(_font, dlist[pos].bytes, _x + r.x(), ypos, r.w(), bytesColor); |
561 | } |
562 | } |
563 | } |
564 | else |
565 | { |
566 | // Draw disassembly, giving it all remaining horizontal space |
567 | s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, |
568 | noTypeDisasmW, textColor); |
569 | } |
570 | } |
571 | } |
572 | |
573 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
574 | Common::Rect RomListWidget::getLineRect() const |
575 | { |
576 | const int yoffset = std::max(0, (_selectedItem - _currentPos) * _fontHeight), |
577 | xoffset = CheckboxWidget::boxSize() + 10; |
578 | |
579 | return Common::Rect(2 + xoffset, 1 + yoffset, |
580 | _w - (xoffset - 15), _fontHeight + yoffset); |
581 | } |
582 | |
583 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
584 | Common::Rect RomListWidget::getEditRect() const |
585 | { |
586 | const int yoffset = std::max(0, (_selectedItem - _currentPos) * _fontHeight); |
587 | |
588 | return Common::Rect(2 + _w - _bytesWidth, 1 + yoffset, |
589 | _w, _fontHeight + yoffset); |
590 | } |
591 | |
592 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
593 | void RomListWidget::startEditMode() |
594 | { |
595 | if (isEditable() && !_editMode && _selectedItem >= 0) |
596 | { |
597 | // Does this line represent an editable area? |
598 | if(myDisasm->list[_selectedItem].bytes == "" ) |
599 | return; |
600 | |
601 | _editMode = true; |
602 | switch(myDisasm->list[_selectedItem].type) |
603 | { |
604 | case CartDebug::GFX: |
605 | case CartDebug::PGFX: |
606 | _base = DiStella::settings.gfxFormat; |
607 | break; |
608 | default: |
609 | _base = Common::Base::format(); |
610 | } |
611 | |
612 | // Widget gets raw data while editing |
613 | EditableWidget::startEditMode(); |
614 | setText(myDisasm->list[_selectedItem].bytes); |
615 | } |
616 | } |
617 | |
618 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
619 | void RomListWidget::endEditMode() |
620 | { |
621 | if (!_editMode) |
622 | return; |
623 | |
624 | // Send a message that editing finished with a return/enter key press |
625 | // The parent then calls getText() to get the newly entered data |
626 | _editMode = false; |
627 | sendCommand(RomListWidget::kRomChangedCmd, _selectedItem, _base); |
628 | |
629 | // Reset to normal data entry |
630 | EditableWidget::endEditMode(); |
631 | } |
632 | |
633 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
634 | void RomListWidget::abortEditMode() |
635 | { |
636 | // Undo any changes made |
637 | _editMode = false; |
638 | |
639 | // Reset to normal data entry |
640 | EditableWidget::abortEditMode(); |
641 | } |
642 | |