mirror of https://github.com/stella-emu/stella.git
OK, I've finally gotten back to Stella development and fixing the
disassembler. Hopefully this will lead to a new release very soon. Added 'autocode' commandline argument and associated UI item (in the RomWidget debugger area), which controls how Distella will use the 'automatic code determination' option. If set to 0/never, this is completely disabled. If set to 1/always, it is always enabled. The default is 2/automatic, whereby it is first turned on, and then turned off if the disassembly doesn't contain the current PC address. RomListWidget has now been completely reworked, so that it informs RomWidget of its intent to change breakpoints and patch ROM. If either of these fail, the action won't be performed, and more importantly, it won't appear onscreen as if the action has succeeded. This fixes an old bug whereby patching could fail, yet the onscreen ROM data was actually changed. Related to this, the list has been made as efficient as possible, and its contents are never un-necessarily copied. Also, lines in the disassembly that cannot be modified no longer show an edit area. Due to the way the new disassembly works, you can no longer switch between banks in the RomWidget (Distella would probably fail to disassemble in such as case). EditTextWidget can now indicate its contents have changed when adding text to it. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1966 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
2cc0d60940
commit
0ed4a9fa79
|
@ -1025,6 +1025,12 @@
|
|||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-autocode <0|1|2></pre></td>
|
||||
<td>Try to differentiate between code vs. data sections in the
|
||||
disassembler. See the Debugger section for more information.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><pre>-debuggerres <WxH></pre></td>
|
||||
<td>Set the size of the debugger window.</td>
|
||||
|
|
|
@ -184,61 +184,88 @@ string CartDebug::toString()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDebug::disassemble(bool autocode)
|
||||
bool CartDebug::disassemble(const string& autocode, bool force)
|
||||
{
|
||||
// Test current disassembly; don't re-disassemble if it hasn't changed
|
||||
// ...
|
||||
bool changed = myConsole.cartridge().bankChanged();
|
||||
// Also check if the current PC is in the current list
|
||||
uInt16 PC = myDebugger.cpuDebug().pc();
|
||||
bool changed = force || myConsole.cartridge().bankChanged() ||
|
||||
(addressToLine(PC) == -1);
|
||||
if(changed)
|
||||
{
|
||||
myDisassembly.clear();
|
||||
myAddrToLineList.clear();
|
||||
|
||||
// We only use the reset vector when we're actually in the startup bank
|
||||
// Otherwise, we look at previous accesses to this bank to begin
|
||||
// If no previous address exists, use the current program counter
|
||||
uInt16 start = myStartAddresses[getBank()];
|
||||
if(start == 0)
|
||||
start = myStartAddresses[getBank()] = PC;
|
||||
|
||||
// For now, DiStella can't handle address space below 0x1000
|
||||
if(!(start & 0x1000))
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
cerr << "start addresses: ";
|
||||
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i) cerr << " " << setw(4) << hex << myStartAddresses[i];
|
||||
cerr << endl;
|
||||
cerr << "current bank = " << getBank() << ", start bank = " << myConsole.cartridge().startBank() << endl
|
||||
<< "reset = " << hex << 0xfffc << ", pc = " << hex << myDebugger.cpuDebug().pc() << endl
|
||||
<< "start = " << hex << start << endl;
|
||||
if(start == 0)
|
||||
start = myStartAddresses[getBank()] = myDebugger.cpuDebug().pc();
|
||||
cerr << "actual start = " << hex << start << endl << endl;
|
||||
<< "reset = " << hex << 0xfffc << ", pc = " << hex << PC << endl
|
||||
<< "start = " << hex << start << endl << endl;
|
||||
#endif
|
||||
|
||||
// For now, DiStella can't handle address space below 0x1000
|
||||
if(!(start & 0x1000))
|
||||
return true;
|
||||
|
||||
autocode = false;
|
||||
DiStella distella(myDisassembly, start, autocode);
|
||||
|
||||
// Parts of the disassembly will be accessed later in different ways
|
||||
// We place those parts in separate maps, to speed up access
|
||||
for(uInt32 i = 0; i < myDisassembly.size(); ++i)
|
||||
// Check whether to use the 'autocode' functionality from Distella
|
||||
if(autocode == "0") // 'never'
|
||||
fillDisassemblyList(start, false, PC);
|
||||
else if(autocode == "1") // always
|
||||
fillDisassemblyList(start, true, PC);
|
||||
else // automatic
|
||||
{
|
||||
const DisassemblyTag& tag = myDisassembly[i];
|
||||
|
||||
// Create a mapping from addresses to line numbers
|
||||
if(tag.address != 0)
|
||||
myAddrToLineList.insert(make_pair(tag.address, i));
|
||||
|
||||
// TODO - look at list, extract address to label mappings
|
||||
// we need these for label support in the UI and promptwidget
|
||||
// First try with autocode on, then turn off if PC isn't found
|
||||
if(!fillDisassemblyList(start, true, PC))
|
||||
fillDisassemblyList(start, false, PC);
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartDebug::fillDisassemblyList(uInt16 start, bool autocode, uInt16 search)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
myDisassembly.clear();
|
||||
DiStella distella(myDisassembly, start, autocode);
|
||||
|
||||
// Parts of the disassembly will be accessed later in different ways
|
||||
// We place those parts in separate maps, to speed up access
|
||||
myAddrToLineList.clear();
|
||||
for(uInt32 i = 0; i < myDisassembly.size(); ++i)
|
||||
{
|
||||
const DisassemblyTag& tag = myDisassembly[i];
|
||||
|
||||
// Only non-zero addresses are valid
|
||||
if(tag.address != 0)
|
||||
{
|
||||
// Create a mapping from addresses to line numbers
|
||||
myAddrToLineList.insert(make_pair(tag.address, i));
|
||||
|
||||
// Did we find the search value?
|
||||
if(tag.address == search)
|
||||
found = true;
|
||||
}
|
||||
|
||||
// TODO - look at list, extract address to label mappings
|
||||
// we need these for label support in the UI and promptwidget
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int CartDebug::addressToLine(uInt16 address) const
|
||||
{
|
||||
map<uInt16, int>::const_iterator iter = myAddrToLineList.find(address);
|
||||
return iter != myAddrToLineList.end() ? iter->second : 0;
|
||||
return iter != myAddrToLineList.end() ? iter->second : -1;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -100,9 +100,12 @@ class CartDebug : public DebuggerSystem
|
|||
Disassemble from the given address using the Distella disassembler
|
||||
Address-to-label mappings (and vice-versa) are also determined here
|
||||
|
||||
@param autocode Whether to determine code vs data sections
|
||||
@param force Force a re-disassembly, even if the state hasn't changed
|
||||
|
||||
@return True if disassembly changed from previous call, else false
|
||||
*/
|
||||
bool disassemble(bool autocode);
|
||||
bool disassemble(const string& autocode, bool force = false);
|
||||
|
||||
/**
|
||||
Get the results from the most recent call to disassemble()
|
||||
|
@ -178,6 +181,10 @@ class CartDebug : public DebuggerSystem
|
|||
};
|
||||
AddrType addressType(uInt16 addr) const;
|
||||
|
||||
// Actually call DiStella to fill the DisassemblyList structure
|
||||
// Return whether the search address was actually in the list
|
||||
bool fillDisassemblyList(uInt16 start, bool autocode, uInt16 search);
|
||||
|
||||
// Extract labels and values from the given character stream
|
||||
string extractLabel(char *c) const;
|
||||
int extractValue(char *c) const;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
DiStella::DiStella(CartDebug::DisassemblyList& list, uInt16 start,
|
||||
bool autocode)
|
||||
: myList(list),
|
||||
labels(NULL) /* array of information about addresses-- can be from 2K-48K bytes in size */
|
||||
labels(NULL) /* array of information about addresses */
|
||||
{
|
||||
while(!myAddressQueue.empty())
|
||||
myAddressQueue.pop();
|
||||
|
|
|
@ -49,8 +49,7 @@ class DiStella
|
|||
@param start The address at which to start disassembly
|
||||
@param autocode If enabled, try to determine code vs. data sections
|
||||
*/
|
||||
DiStella(CartDebug::DisassemblyList& list, uInt16 start,
|
||||
bool autocode = true);
|
||||
DiStella(CartDebug::DisassemblyList& list, uInt16 start, bool autocode = true);
|
||||
|
||||
~DiStella();
|
||||
|
||||
|
|
|
@ -19,49 +19,63 @@
|
|||
#include "bspf.hxx"
|
||||
#include "PackedBitArray.hxx"
|
||||
|
||||
PackedBitArray::PackedBitArray(int length) {
|
||||
size = length;
|
||||
words = length / wordSize + 1;
|
||||
bits = new unsigned int[ words ];
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PackedBitArray::PackedBitArray(uInt32 length)
|
||||
: size(length),
|
||||
words(length / wordSize + 1)
|
||||
{
|
||||
bits = new uInt32[ words ];
|
||||
|
||||
for(int i=0; i<words; i++)
|
||||
for(uInt32 i = 0; i < words; ++i)
|
||||
bits[i] = 0;
|
||||
}
|
||||
|
||||
PackedBitArray::~PackedBitArray() {
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PackedBitArray::~PackedBitArray()
|
||||
{
|
||||
delete[] bits;
|
||||
}
|
||||
|
||||
int PackedBitArray::isSet(unsigned int bit) {
|
||||
unsigned int word = bit / wordSize;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 PackedBitArray::isSet(uInt32 bit) const
|
||||
{
|
||||
uInt32 word = bit / wordSize;
|
||||
bit %= wordSize;
|
||||
|
||||
return (bits[word] & (1 << bit));
|
||||
}
|
||||
|
||||
int PackedBitArray::isClear(unsigned int bit) {
|
||||
unsigned int word = bit / wordSize;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 PackedBitArray::isClear(uInt32 bit) const
|
||||
{
|
||||
uInt32 word = bit / wordSize;
|
||||
bit %= wordSize;
|
||||
|
||||
return !(bits[word] & (1 << bit));
|
||||
}
|
||||
|
||||
void PackedBitArray::toggle(unsigned int bit) {
|
||||
unsigned int word = bit / wordSize;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PackedBitArray::toggle(uInt32 bit)
|
||||
{
|
||||
uInt32 word = bit / wordSize;
|
||||
bit %= wordSize;
|
||||
|
||||
bits[word] ^= (1 << bit);
|
||||
}
|
||||
|
||||
void PackedBitArray::set(unsigned int bit) {
|
||||
unsigned int word = bit / wordSize;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PackedBitArray::set(uInt32 bit)
|
||||
{
|
||||
uInt32 word = bit / wordSize;
|
||||
bit %= wordSize;
|
||||
|
||||
bits[word] |= (1 << bit);
|
||||
}
|
||||
|
||||
void PackedBitArray::clear(unsigned int bit) {
|
||||
unsigned int word = bit / wordSize;
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PackedBitArray::clear(uInt32 bit)
|
||||
{
|
||||
uInt32 word = bit / wordSize;
|
||||
bit %= wordSize;
|
||||
|
||||
bits[word] &= (~(1 << bit));
|
||||
|
|
|
@ -23,27 +23,28 @@
|
|||
|
||||
#define wordSize ( (sizeof(unsigned int)) * 8)
|
||||
|
||||
class PackedBitArray {
|
||||
class PackedBitArray
|
||||
{
|
||||
public:
|
||||
PackedBitArray(int length);
|
||||
PackedBitArray(uInt32 length);
|
||||
~PackedBitArray();
|
||||
|
||||
int isSet(unsigned int bit);
|
||||
int isClear(unsigned int bit);
|
||||
uInt32 isSet(uInt32 bit) const;
|
||||
uInt32 isClear(uInt32 bit) const;
|
||||
|
||||
void set(unsigned int bit);
|
||||
void clear(unsigned int bit);
|
||||
void toggle(unsigned int bit);
|
||||
void set(uInt32 bit);
|
||||
void clear(uInt32 bit);
|
||||
void toggle(uInt32 bit);
|
||||
|
||||
private:
|
||||
// number of bits in the array:
|
||||
int size;
|
||||
uInt32 size;
|
||||
|
||||
// number of unsigned ints (size/wordSize):
|
||||
int words;
|
||||
uInt32 words;
|
||||
|
||||
// the array itself:
|
||||
unsigned int *bits;
|
||||
uInt32* bits;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -516,7 +516,6 @@ void DataGridWidget::drawWidget(bool hilite)
|
|||
//cerr << "DataGridWidget::drawWidget\n";
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
int row, col, deltax;
|
||||
string buffer;
|
||||
|
||||
// Draw the internal grid and labels
|
||||
int linewidth = _cols * _colWidth;
|
||||
|
@ -542,16 +541,14 @@ void DataGridWidget::drawWidget(bool hilite)
|
|||
|
||||
if (_selectedItem == pos && _editMode)
|
||||
{
|
||||
buffer = _editString;
|
||||
adjustOffset();
|
||||
deltax = -_editScrollOffset;
|
||||
|
||||
s.drawString(_font, buffer, x, y, _colWidth, kTextColor,
|
||||
s.drawString(_font, _editString, x, y, _colWidth, kTextColor,
|
||||
kTextAlignLeft, deltax, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _valueStringList[pos];
|
||||
deltax = 0;
|
||||
|
||||
uInt32 color = kTextColor;
|
||||
|
@ -567,7 +564,7 @@ void DataGridWidget::drawWidget(bool hilite)
|
|||
else if(_hiliteList[pos])
|
||||
color = kDbgColorHi;
|
||||
|
||||
s.drawString(_font, buffer, x, y, _colWidth, color);
|
||||
s.drawString(_font, _valueStringList[pos], x, y, _colWidth, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,17 +20,44 @@
|
|||
//============================================================================
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Debugger.hxx"
|
||||
#include "ContextMenu.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "ScrollBarWidget.hxx"
|
||||
#include "RomListWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int w, int h)
|
||||
: CheckListWidget(boss, font, x, y, w, h),
|
||||
myMenu(NULL)
|
||||
: EditableWidget(boss, font, x, y, 16, 16),
|
||||
myMenu(NULL),
|
||||
_rows(0),
|
||||
_cols(0),
|
||||
_currentPos(0),
|
||||
_selectedItem(-1),
|
||||
_highlightedItem(-1),
|
||||
_currentKeyDown(0),
|
||||
_editMode(false)
|
||||
{
|
||||
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
|
||||
_type = kRomListWidget;
|
||||
_bgcolor = kWidColor;
|
||||
_bgcolorhi = kWidColor;
|
||||
_textcolor = kTextColor;
|
||||
_textcolorhi = kTextColor;
|
||||
|
||||
_cols = w / _fontWidth;
|
||||
_rows = h / _fontHeight;
|
||||
|
||||
// Set real dimensions
|
||||
_w = w - kScrollBarWidth;
|
||||
_h = h + 2;
|
||||
|
||||
// Create scrollbar and attach to the list
|
||||
myScrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h);
|
||||
myScrollBar->setTarget(this);
|
||||
|
||||
// Add context menu
|
||||
StringMap l;
|
||||
// l.push_back("Add bookmark");
|
||||
l.push_back("Save ROM", "saverom");
|
||||
|
@ -43,6 +70,30 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& font,
|
|||
|
||||
myLabelWidth = BSPF_max(16, int(0.35 * (numchars - 12))) * fontWidth;
|
||||
myBytesWidth = 12 * fontWidth;
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Add checkboxes
|
||||
int ypos = _y + 2;
|
||||
|
||||
// rowheight is determined by largest item on a line,
|
||||
// possibly meaning that number of rows will change
|
||||
_fontHeight = BSPF_max(_fontHeight, CheckboxWidget::boxSize());
|
||||
_rows = h / _fontHeight;
|
||||
|
||||
// Create a CheckboxWidget for each row in the list
|
||||
CheckboxWidget* t;
|
||||
for(int i = 0; i < _rows; ++i)
|
||||
{
|
||||
t = new CheckboxWidget(boss, font, _x + 2, ypos, "", kCheckActionCmd);
|
||||
t->setTarget(this);
|
||||
t->setID(i);
|
||||
t->drawBox(false);
|
||||
t->setFill(true);
|
||||
t->setTextColor(kTextColorEm);
|
||||
ypos += _fontHeight;
|
||||
|
||||
myCheckList.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -53,20 +104,115 @@ RomListWidget::~RomListWidget()
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::setList(const CartDebug::DisassemblyList& list,
|
||||
const BoolArray& state)
|
||||
const PackedBitArray& state)
|
||||
{
|
||||
myList = &list;
|
||||
myBPState = &state;
|
||||
|
||||
// TODO - maybe there's a better way than copying all the bytes again??
|
||||
StringList bytes;
|
||||
for(uInt32 i = 0; i < list.size(); ++i)
|
||||
bytes.push_back(list[i].bytes);
|
||||
CheckListWidget::setList(bytes, state);
|
||||
// Enable all checkboxes
|
||||
for(int i = 0; i < _rows; ++i)
|
||||
myCheckList[i]->setFlags(WIDGET_ENABLED);
|
||||
|
||||
// Then turn off any extras
|
||||
if((int)myList->size() < _rows)
|
||||
for(int i = myList->size(); i < _rows; ++i)
|
||||
myCheckList[i]->clearFlags(WIDGET_ENABLED);
|
||||
|
||||
recalc();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::setHighlighted(int item)
|
||||
{
|
||||
if(item < -1 || item >= (int)myList->size())
|
||||
return;
|
||||
|
||||
if(isEnabled())
|
||||
{
|
||||
if(_editMode)
|
||||
abortEditMode();
|
||||
|
||||
_highlightedItem = item;
|
||||
|
||||
// Only scroll the list if we're about to pass the page boundary
|
||||
if(_currentPos == 0)
|
||||
_currentPos = _highlightedItem;
|
||||
else if(_highlightedItem == _currentPos + _rows)
|
||||
_currentPos += _rows;
|
||||
|
||||
scrollToHighlighted();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const string& RomListWidget::getEditString() const
|
||||
{
|
||||
if(_selectedItem < -1 || _selectedItem >= (int)myList->size())
|
||||
return EmptyString;
|
||||
else
|
||||
return _editString;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int RomListWidget::findItem(int x, int y) const
|
||||
{
|
||||
return (y - 1) / _fontHeight + _currentPos;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::recalc()
|
||||
{
|
||||
int size = myList->size();
|
||||
|
||||
if (_currentPos >= size)
|
||||
_currentPos = size - 1;
|
||||
if (_currentPos < 0)
|
||||
_currentPos = 0;
|
||||
|
||||
if(_selectedItem < 0 || _selectedItem >= size)
|
||||
_selectedItem = 0;
|
||||
|
||||
_editMode = false;
|
||||
|
||||
myScrollBar->_numEntries = myList->size();
|
||||
myScrollBar->_entriesPerPage = _rows;
|
||||
|
||||
// Reset to normal data entry
|
||||
abortEditMode();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::scrollToCurrent(int item)
|
||||
{
|
||||
// Only do something if the current item is not in our view port
|
||||
if (item < _currentPos)
|
||||
{
|
||||
// it's above our view
|
||||
_currentPos = item;
|
||||
}
|
||||
else if (item >= _currentPos + _rows )
|
||||
{
|
||||
// it's below our view
|
||||
_currentPos = item - _rows + 1;
|
||||
}
|
||||
|
||||
if (_currentPos < 0 || _rows > (int)myList->size())
|
||||
_currentPos = 0;
|
||||
else if (_currentPos + _rows > (int)myList->size())
|
||||
_currentPos = myList->size() - _rows;
|
||||
|
||||
myScrollBar->_currentPos = _currentPos;
|
||||
myScrollBar->recalc();
|
||||
|
||||
setDirty(); draw();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::handleMouseDown(int x, int y, int button, int clickCount)
|
||||
{
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
// Grab right mouse button for context menu, send left to base class
|
||||
if(button == 2)
|
||||
{
|
||||
|
@ -74,13 +220,184 @@ void RomListWidget::handleMouseDown(int x, int y, int button, int clickCount)
|
|||
myMenu->show(x + getAbsX(), y + getAbsY());
|
||||
}
|
||||
else
|
||||
ListWidget::handleMouseDown(x, y, button, clickCount);
|
||||
{
|
||||
// First check whether the selection changed
|
||||
int newSelectedItem;
|
||||
newSelectedItem = findItem(x, y);
|
||||
if (newSelectedItem > (int)myList->size() - 1)
|
||||
newSelectedItem = -1;
|
||||
|
||||
if (_selectedItem != newSelectedItem)
|
||||
{
|
||||
if (_editMode)
|
||||
abortEditMode();
|
||||
_selectedItem = newSelectedItem;
|
||||
setDirty(); draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::handleMouseUp(int x, int y, int button, int clickCount)
|
||||
{
|
||||
// If this was a double click and the mouse is still over the selected item,
|
||||
// send the double click command
|
||||
if (clickCount == 2 && (_selectedItem == findItem(x, y)))
|
||||
{
|
||||
// Start edit mode
|
||||
if(_editable && !_editMode)
|
||||
startEditMode();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::handleMouseWheel(int x, int y, int direction)
|
||||
{
|
||||
myScrollBar->handleMouseWheel(x, y, direction);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomListWidget::handleKeyDown(int ascii, int keycode, int modifiers)
|
||||
{
|
||||
// Ignore all Alt-mod keys
|
||||
if(instance().eventHandler().kbdAlt(modifiers))
|
||||
return true;
|
||||
|
||||
bool handled = true;
|
||||
int oldSelectedItem = _selectedItem;
|
||||
|
||||
if (_editMode)
|
||||
{
|
||||
// Class EditableWidget handles all text editing related key presses for us
|
||||
handled = EditableWidget::handleKeyDown(ascii, keycode, modifiers);
|
||||
}
|
||||
else
|
||||
{
|
||||
// not editmode
|
||||
switch (keycode)
|
||||
{
|
||||
case ' ': // space
|
||||
// Snap list back to currently highlighted line
|
||||
if(_highlightedItem >= 0)
|
||||
{
|
||||
_currentPos = _highlightedItem;
|
||||
scrollToHighlighted();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_selectedItem != oldSelectedItem)
|
||||
{
|
||||
myScrollBar->draw();
|
||||
scrollToSelected();
|
||||
}
|
||||
|
||||
_currentKeyDown = keycode;
|
||||
return handled;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomListWidget::handleKeyUp(int ascii, int keycode, int modifiers)
|
||||
{
|
||||
if (keycode == _currentKeyDown)
|
||||
_currentKeyDown = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomListWidget::handleEvent(Event::Type e)
|
||||
{
|
||||
return ListWidget::handleEvent(e); // override CheckListWidget::handleEvent()
|
||||
if(!isEnabled() || _editMode)
|
||||
return false;
|
||||
|
||||
bool handled = true;
|
||||
int oldSelectedItem = _selectedItem;
|
||||
|
||||
switch(e)
|
||||
{
|
||||
case Event::UISelect:
|
||||
if (_selectedItem >= 0)
|
||||
{
|
||||
if (_editable)
|
||||
startEditMode();
|
||||
}
|
||||
break;
|
||||
|
||||
case Event::UIUp:
|
||||
if (_selectedItem > 0)
|
||||
_selectedItem--;
|
||||
break;
|
||||
|
||||
case Event::UIDown:
|
||||
if (_selectedItem < (int)myList->size() - 1)
|
||||
_selectedItem++;
|
||||
break;
|
||||
|
||||
case Event::UIPgUp:
|
||||
_selectedItem -= _rows - 1;
|
||||
if (_selectedItem < 0)
|
||||
_selectedItem = 0;
|
||||
break;
|
||||
|
||||
case Event::UIPgDown:
|
||||
_selectedItem += _rows - 1;
|
||||
if (_selectedItem >= (int)myList->size() )
|
||||
_selectedItem = myList->size() - 1;
|
||||
break;
|
||||
|
||||
case Event::UIHome:
|
||||
_selectedItem = 0;
|
||||
break;
|
||||
|
||||
case Event::UIEnd:
|
||||
_selectedItem = myList->size() - 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
|
||||
if (_selectedItem != oldSelectedItem)
|
||||
{
|
||||
myScrollBar->draw();
|
||||
scrollToSelected();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case kCheckActionCmd:
|
||||
// We let the parent class handle this
|
||||
// Pass it as a kRLBreakpointChangedCmd command, since that's the intent
|
||||
sendCommand(kRLBreakpointChangedCmd, myCheckList[id]->getState(), _currentPos+id);
|
||||
break;
|
||||
|
||||
case kSetPositionCmd:
|
||||
if (_currentPos != (int)data)
|
||||
{
|
||||
_currentPos = data;
|
||||
setDirty(); draw();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::lostFocusWidget()
|
||||
{
|
||||
_editMode = false;
|
||||
|
||||
// Reset to normal data entry
|
||||
abortEditMode();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -90,7 +407,6 @@ void RomListWidget::drawWidget(bool hilite)
|
|||
FBSurface& s = _boss->dialog().surface();
|
||||
const CartDebug::DisassemblyList& dlist = *myList;
|
||||
int i, pos, xpos, ypos, len = dlist.size();
|
||||
string buffer;
|
||||
int deltax;
|
||||
|
||||
// Draw a thin frame around the list and to separate columns
|
||||
|
@ -101,15 +417,15 @@ void RomListWidget::drawWidget(bool hilite)
|
|||
s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor);
|
||||
|
||||
// Draw the list items
|
||||
GUI::Rect r = getEditRect();
|
||||
GUI::Rect l = getLineRect();
|
||||
const GUI::Rect& r = getEditRect();
|
||||
const GUI::Rect& l = getLineRect();
|
||||
xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2;
|
||||
for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight)
|
||||
{
|
||||
// Draw checkboxes for correct lines (takes scrolling into account)
|
||||
_checkList[i]->setState(_stateList[pos]);
|
||||
_checkList[i]->setDirty();
|
||||
_checkList[i]->draw();
|
||||
myCheckList[i]->setState(myBPState->isSet(dlist[pos].address));
|
||||
myCheckList[i]->setDirty();
|
||||
myCheckList[i]->draw();
|
||||
|
||||
// Draw highlighted item in a frame
|
||||
if (_highlightedItem == pos)
|
||||
|
@ -140,24 +456,22 @@ void RomListWidget::drawWidget(bool hilite)
|
|||
// Draw editable bytes
|
||||
if (_selectedItem == pos && _editMode)
|
||||
{
|
||||
buffer = _editString;
|
||||
adjustOffset();
|
||||
deltax = -_editScrollOffset;
|
||||
|
||||
s.drawString(_font, buffer, _x + r.left, ypos, r.width(), kTextColor,
|
||||
s.drawString(_font, _editString, _x + r.left, ypos, r.width(), kTextColor,
|
||||
kTextAlignLeft, deltax, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _list[pos];
|
||||
deltax = 0;
|
||||
s.drawString(_font, buffer, _x + r.left, ypos, r.width(), kTextColor);
|
||||
s.drawString(_font, dlist[pos].bytes, _x + r.left, ypos, r.width(), kTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
// Only draw the caret while editing, and if it's in the current viewport
|
||||
if(_editMode && (_selectedItem >= _scrollBar->_currentPos) &&
|
||||
(_selectedItem < _scrollBar->_currentPos + _rows))
|
||||
if(_editMode && (_selectedItem >= myScrollBar->_currentPos) &&
|
||||
(_selectedItem < myScrollBar->_currentPos + _rows))
|
||||
drawCaret();
|
||||
}
|
||||
|
||||
|
@ -202,3 +516,45 @@ bool RomListWidget::tryInsertChar(char c, int pos)
|
|||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::startEditMode()
|
||||
{
|
||||
if (_editable && !_editMode && _selectedItem >= 0)
|
||||
{
|
||||
// Does this line represent an editable area?
|
||||
if((*myList)[_selectedItem].bytes == "")
|
||||
return;
|
||||
|
||||
_editMode = true;
|
||||
|
||||
// Widget gets raw data while editing
|
||||
EditableWidget::startEditMode();
|
||||
setEditString((*myList)[_selectedItem].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::endEditMode()
|
||||
{
|
||||
if (!_editMode)
|
||||
return;
|
||||
|
||||
// Send a message that editing finished with a return/enter key press
|
||||
// The parent then calls getEditString() to get the newly entered data
|
||||
_editMode = false;
|
||||
sendCommand(kRLRomChangedCmd, _selectedItem, _id);
|
||||
|
||||
// Reset to normal data entry
|
||||
EditableWidget::endEditMode();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomListWidget::abortEditMode()
|
||||
{
|
||||
// Undo any changes made
|
||||
_editMode = false;
|
||||
|
||||
// Reset to normal data entry
|
||||
EditableWidget::abortEditMode();
|
||||
}
|
||||
|
|
|
@ -22,14 +22,24 @@
|
|||
#ifndef ROM_LIST_WIDGET_HXX
|
||||
#define ROM_LIST_WIDGET_HXX
|
||||
|
||||
class CheckboxWidget;
|
||||
class ContextMenu;
|
||||
class ScrollBarWidget;
|
||||
class PackedBitArray;
|
||||
|
||||
#include "Array.hxx"
|
||||
#include "StringList.hxx"
|
||||
#include "CheckListWidget.hxx"
|
||||
#include "CartDebug.hxx"
|
||||
#include "EditableWidget.hxx"
|
||||
|
||||
// Some special commands for this widget
|
||||
enum {
|
||||
kRLBreakpointChangedCmd = 'RLbp', // click on the checkbox for a breakpoint
|
||||
kRLRomChangedCmd = 'RLpr' // ROM item data changed - 'data' will be item index
|
||||
};
|
||||
|
||||
/** RomListWidget */
|
||||
class RomListWidget : public CheckListWidget
|
||||
class RomListWidget : public EditableWidget
|
||||
{
|
||||
friend class RomWidget;
|
||||
|
||||
|
@ -38,24 +48,60 @@ class RomListWidget : public CheckListWidget
|
|||
int x, int y, int w, int h);
|
||||
virtual ~RomListWidget();
|
||||
|
||||
void setList(const CartDebug::DisassemblyList& list, const BoolArray& state);
|
||||
void setList(const CartDebug::DisassemblyList& list, const PackedBitArray& state);
|
||||
|
||||
int getSelected() const { return _selectedItem; }
|
||||
int getHighlighted() const { return _highlightedItem; }
|
||||
void setHighlighted(int item);
|
||||
|
||||
const string& getEditString() const;
|
||||
void startEditMode();
|
||||
void endEditMode();
|
||||
|
||||
protected:
|
||||
void handleMouseDown(int x, int y, int button, int clickCount);
|
||||
void handleMouseUp(int x, int y, int button, int clickCount);
|
||||
void handleMouseWheel(int x, int y, int direction);
|
||||
bool handleKeyDown(int ascii, int keycode, int modifiers);
|
||||
bool handleKeyUp(int ascii, int keycode, int modifiers);
|
||||
bool handleEvent(Event::Type e);
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id);
|
||||
|
||||
void drawWidget(bool hilite);
|
||||
GUI::Rect getLineRect() const;
|
||||
GUI::Rect getEditRect() const;
|
||||
|
||||
int findItem(int x, int y) const;
|
||||
void recalc();
|
||||
|
||||
bool tryInsertChar(char c, int pos);
|
||||
|
||||
void abortEditMode();
|
||||
void lostFocusWidget();
|
||||
void scrollToSelected() { scrollToCurrent(_selectedItem); }
|
||||
void scrollToHighlighted() { scrollToCurrent(_highlightedItem); }
|
||||
|
||||
private:
|
||||
void scrollToCurrent(int item);
|
||||
|
||||
private:
|
||||
ContextMenu* myMenu;
|
||||
ScrollBarWidget* myScrollBar;
|
||||
|
||||
int myLabelWidth;
|
||||
int myBytesWidth;
|
||||
|
||||
int _rows;
|
||||
int _cols;
|
||||
int _currentPos;
|
||||
int _selectedItem;
|
||||
int _highlightedItem;
|
||||
int _currentKeyDown;
|
||||
bool _editMode;
|
||||
|
||||
const CartDebug::DisassemblyList* myList;
|
||||
const PackedBitArray* myBPState;
|
||||
Common::Array<CheckboxWidget*> myCheckList;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
#include "DebuggerParser.hxx"
|
||||
#include "CartDebug.hxx"
|
||||
#include "CpuDebug.hxx"
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "PackedBitArray.hxx"
|
||||
#include "GuiObject.hxx"
|
||||
#include "InputTextDialog.hxx"
|
||||
#include "EditTextWidget.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "StringList.hxx"
|
||||
#include "ContextMenu.hxx"
|
||||
#include "RomListWidget.hxx"
|
||||
#include "RomWidget.hxx"
|
||||
|
@ -45,45 +45,50 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y)
|
|||
|
||||
int xpos, ypos;
|
||||
StaticTextWidget* t;
|
||||
WidgetArray wid;
|
||||
|
||||
// Create bank editable area
|
||||
xpos = x + 40; ypos = y + 7;
|
||||
// Show current bank
|
||||
xpos = x; ypos = y + 7;
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos,
|
||||
font.getStringWidth("Current bank: "),
|
||||
font.getStringWidth("Bank (current/total):"),
|
||||
font.getFontHeight(),
|
||||
"Current bank:", kTextAlignLeft);
|
||||
"Bank (current/total):", kTextAlignLeft);
|
||||
|
||||
xpos += t->getWidth() + 10;
|
||||
myBank = new DataGridWidget(boss, font, xpos, ypos-2,
|
||||
1, 1, 4, 8, kBASE_10);
|
||||
myBank->setTarget(this);
|
||||
myBank->setRange(0, instance().debugger().cartDebug().bankCount());
|
||||
if(instance().debugger().cartDebug().bankCount() <= 1)
|
||||
myBank = new EditTextWidget(boss, font, xpos, ypos-2,
|
||||
4 * font.getMaxCharWidth(),
|
||||
font.getLineHeight(), "");
|
||||
myBank->setEditable(false);
|
||||
addFocusWidget(myBank);
|
||||
|
||||
// Show number of banks
|
||||
xpos += myBank->getWidth() + 45;
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos,
|
||||
font.getStringWidth("Total banks: "),
|
||||
font.getFontHeight(),
|
||||
"Total banks:", kTextAlignLeft);
|
||||
|
||||
xpos += t->getWidth() + 10;
|
||||
myBankCount = new EditTextWidget(boss, font, xpos, ypos-2,
|
||||
font.getStringWidth("XXXX"),
|
||||
xpos += myBank->getWidth() + 5;
|
||||
myBankCount =
|
||||
new EditTextWidget(boss, font, xpos, ypos-2, 4 * font.getMaxCharWidth(),
|
||||
font.getLineHeight(), "");
|
||||
myBankCount->setEditable(false);
|
||||
|
||||
// 'Autocode' setting for Distella
|
||||
xpos += myBankCount->getWidth() + 20;
|
||||
StringMap items;
|
||||
items.push_back("Never", "0");
|
||||
items.push_back("Always", "1");
|
||||
items.push_back("Automatic", "2");
|
||||
myAutocode =
|
||||
new PopUpWidget(boss, font, xpos, ypos-2, font.getStringWidth("Automatic"),
|
||||
font.getLineHeight(), items,
|
||||
"Determine code: ", font.getStringWidth("Determine code: "),
|
||||
kAutocodeChanged);
|
||||
myAutocode->setTarget(this);
|
||||
addFocusWidget(myAutocode);
|
||||
|
||||
// Create rom listing
|
||||
xpos = x; ypos += myBank->getHeight() + 4;
|
||||
GUI::Rect dialog = instance().debugger().getDialogBounds();
|
||||
const GUI::Rect& dialog = instance().debugger().getDialogBounds();
|
||||
int w = dialog.width() - x - 5, h = dialog.height() - ypos - 3;
|
||||
|
||||
myRomList = new RomListWidget(boss, font, xpos, ypos, w, h);
|
||||
myRomList->setTarget(this);
|
||||
myRomList->myMenu->setTarget(this);
|
||||
myRomList->setStyle(kSolidFill);
|
||||
addFocusWidget(myRomList);
|
||||
|
||||
// Calculate real dimensions
|
||||
|
@ -95,6 +100,9 @@ RomWidget::RomWidget(GuiObject* boss, const GUI::Font& font, int x, int y)
|
|||
label.push_back("Filename: ");
|
||||
mySaveRom = new InputTextDialog(boss, font, label);
|
||||
mySaveRom->setTarget(this);
|
||||
|
||||
// By default, we try to automatically determine code vs. data sections
|
||||
myAutocode->setSelected(instance().settings().getString("autocode"), "2");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -103,17 +111,46 @@ RomWidget::~RomWidget()
|
|||
delete mySaveRom;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::loadConfig()
|
||||
{
|
||||
Debugger& dbg = instance().debugger();
|
||||
CartDebug& cart = dbg.cartDebug();
|
||||
bool bankChanged = myCurrentBank != cart.getBank();
|
||||
myCurrentBank = cart.getBank();
|
||||
|
||||
// Fill romlist the current bank of source or disassembly
|
||||
myListIsDirty |= cart.disassemble(myAutocode->getSelectedTag(), myListIsDirty);
|
||||
if(myListIsDirty)
|
||||
{
|
||||
myRomList->setList(cart.disassemblyList(), dbg.breakpoints());
|
||||
myListIsDirty = false;
|
||||
}
|
||||
|
||||
// Update romlist to point to current PC
|
||||
int pcline = cart.addressToLine(dbg.cpuDebug().pc());
|
||||
if(pcline > 0)
|
||||
myRomList->setHighlighted(pcline);
|
||||
|
||||
// Set current bank and number of banks
|
||||
myBank->setEditString(instance().debugger().valueToString(myCurrentBank, kBASE_10), bankChanged);
|
||||
myBankCount->setEditString(instance().debugger().valueToString(cart.bankCount(), kBASE_10));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case kListItemChecked:
|
||||
setBreak(data);
|
||||
case kRLBreakpointChangedCmd:
|
||||
// 'id' is the line in the disassemblylist to be accessed
|
||||
// 'data' is the state of the breakpoint at 'id'
|
||||
setBreak(id, data);
|
||||
break;
|
||||
|
||||
case kListItemDataChangedCmd:
|
||||
patchROM(data, myRomList->getSelectedString());
|
||||
case kRLRomChangedCmd:
|
||||
// 'data' is the line in the disassemblylist to be accessed
|
||||
patchROM(data, myRomList->getEditString());
|
||||
break;
|
||||
|
||||
case kCMenuItemSelectedCmd:
|
||||
|
@ -132,6 +169,12 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|||
break;
|
||||
}
|
||||
|
||||
case kAutocodeChanged:
|
||||
instance().settings().setString("autocode", myAutocode->getSelectedTag());
|
||||
invalidate();
|
||||
loadConfig();
|
||||
break;
|
||||
|
||||
case kRomNameEntered:
|
||||
{
|
||||
const string& rom = mySaveRom->getResult();
|
||||
|
@ -144,108 +187,43 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kDGItemDataChangedCmd:
|
||||
{
|
||||
int bank = myBank->getSelectedValue();
|
||||
instance().debugger().setBank(bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::loadConfig()
|
||||
{
|
||||
Debugger& dbg = instance().debugger();
|
||||
CartDebug& cart = dbg.cartDebug();
|
||||
bool bankChanged = myCurrentBank != cart.getBank();
|
||||
myCurrentBank = cart.getBank();
|
||||
|
||||
// Fill romlist the current bank of source or disassembly
|
||||
// Only reload full bank when necessary
|
||||
// TODO - bank changes aren't the only time that the disassembly needs to
|
||||
// be redone; ROMs which dynamically change cart address space and
|
||||
// have self-modifying code need to be taken into account
|
||||
// As well, we don't always start from the 0xfffc; this only
|
||||
// happens in the startup bank
|
||||
myListIsDirty |= cart.disassemble(true);
|
||||
if(myListIsDirty)
|
||||
{
|
||||
const CartDebug::DisassemblyList& list = cart.disassemblyList();
|
||||
BoolArray state;
|
||||
|
||||
PackedBitArray& bp = dbg.breakpoints();
|
||||
for(uInt32 i = 0; i < list.size(); ++i)
|
||||
{
|
||||
const CartDebug::DisassemblyTag& tag = list[i];
|
||||
if(tag.address != 0 && bp.isSet(tag.address))
|
||||
state.push_back(true);
|
||||
else
|
||||
state.push_back(false);
|
||||
}
|
||||
|
||||
myRomList->setList(list, state);
|
||||
|
||||
// Restore the old bank, in case we inadvertently switched while reading.
|
||||
// dbg.setBank(myCurrentBank); // TODO - why is this here?
|
||||
|
||||
myListIsDirty = false;
|
||||
}
|
||||
|
||||
// Update romlist to point to current PC
|
||||
int pcline = cart.addressToLine(dbg.cpuDebug().pc());
|
||||
if(pcline > 0)
|
||||
myRomList->setHighlighted(pcline);
|
||||
|
||||
// Set current bank
|
||||
IntArray alist;
|
||||
IntArray vlist;
|
||||
BoolArray changed;
|
||||
|
||||
alist.push_back(-1);
|
||||
vlist.push_back(cart.getBank());
|
||||
changed.push_back(bankChanged);
|
||||
myBank->setList(alist, vlist, changed);
|
||||
|
||||
// Indicate total number of banks
|
||||
myBankCount->setEditString(dbg.valueToString(cart.bankCount(), kBASE_10));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::setBreak(int data)
|
||||
void RomWidget::setBreak(int disasm_line, bool state)
|
||||
{
|
||||
const CartDebug::DisassemblyList& list =
|
||||
instance().debugger().cartDebug().disassemblyList();
|
||||
if(data >= (int)list.size()) return;
|
||||
if(disasm_line >= (int)list.size()) return;
|
||||
|
||||
bool state = myRomList->getState(data);
|
||||
if(list[data].address != 0)
|
||||
instance().debugger().setBreakPoint(list[data].address, state);
|
||||
if(list[disasm_line].address != 0)
|
||||
instance().debugger().setBreakPoint(list[disasm_line].address, state);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::setPC(int data)
|
||||
void RomWidget::setPC(int disasm_line)
|
||||
{
|
||||
const CartDebug::DisassemblyList& list =
|
||||
instance().debugger().cartDebug().disassemblyList();
|
||||
if(data >= (int)list.size()) return;
|
||||
if(disasm_line >= (int)list.size()) return;
|
||||
|
||||
if(list[data].address != 0)
|
||||
if(list[disasm_line].address != 0)
|
||||
{
|
||||
ostringstream command;
|
||||
command << "pc #" << list[data].address;
|
||||
command << "pc #" << list[disasm_line].address;
|
||||
instance().debugger().run(command.str());
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomWidget::patchROM(int data, const string& bytes)
|
||||
void RomWidget::patchROM(int disasm_line, const string& bytes)
|
||||
{
|
||||
const CartDebug::DisassemblyList& list =
|
||||
instance().debugger().cartDebug().disassemblyList();
|
||||
if(data >= (int)list.size()) return;
|
||||
if(disasm_line >= (int)list.size()) return;
|
||||
|
||||
if(list[data].address != 0)
|
||||
if(list[disasm_line].address != 0)
|
||||
{
|
||||
ostringstream command;
|
||||
|
||||
|
@ -255,7 +233,7 @@ void RomWidget::patchROM(int data, const string& bytes)
|
|||
BaseFormat oldbase = instance().debugger().parser().base();
|
||||
instance().debugger().parser().setBase(kBASE_16);
|
||||
|
||||
command << "rom #" << list[data].address << " " << bytes;
|
||||
command << "rom #" << list[disasm_line].address << " " << bytes;
|
||||
instance().debugger().run(command.str());
|
||||
|
||||
// Restore previous base
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#define ROM_WIDGET_HXX
|
||||
|
||||
class GuiObject;
|
||||
class DataGridWidget;
|
||||
class EditTextWidget;
|
||||
class InputTextDialog;
|
||||
class PopUpWidget;
|
||||
class RomListWidget;
|
||||
class StringList;
|
||||
|
||||
|
@ -46,19 +46,21 @@ class RomWidget : public Widget, public CommandSender
|
|||
void loadConfig();
|
||||
|
||||
private:
|
||||
void setBreak(int data);
|
||||
void setPC(int data);
|
||||
void patchROM(int data, const string& bytes);
|
||||
void setBreak(int disasm_line, bool state);
|
||||
void setPC(int disasm_line);
|
||||
void patchROM(int disasm_line, const string& bytes);
|
||||
void saveROM(const string& rom);
|
||||
|
||||
private:
|
||||
enum {
|
||||
kAutocodeChanged = 'ACch',
|
||||
kRomNameEntered = 'RWrn'
|
||||
};
|
||||
|
||||
RomListWidget* myRomList;
|
||||
DataGridWidget* myBank;
|
||||
EditTextWidget* myBank;
|
||||
EditTextWidget* myBankCount;
|
||||
PopUpWidget* myAutocode;
|
||||
InputTextDialog* mySaveRom;
|
||||
|
||||
bool myListIsDirty;
|
||||
|
|
|
@ -347,7 +347,7 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
|||
// TODO - this should really be in a method that checks the first
|
||||
// 512 bytes of ROM and finds if either the lower 256 bytes or
|
||||
// higher 256 bytes are all the same. For now, we assume that
|
||||
// all carts of 12K are CBS RAM Plus/FASC.
|
||||
// all carts of 12K are CBS RAM Plus/FA.
|
||||
type = "FA";
|
||||
}
|
||||
else if(size == 16384) // 16K
|
||||
|
|
|
@ -125,6 +125,9 @@ Settings::Settings(OSystem* osystem)
|
|||
setInternal("fastscbios", "false");
|
||||
setExternal("romloadcount", "0");
|
||||
setExternal("maxres", "0x0");
|
||||
|
||||
// Debugger options
|
||||
setInternal("autocode", "2");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -396,6 +399,7 @@ void Settings::usage()
|
|||
<< " The following options are meant for developers\n"
|
||||
<< " Arguments are more fully explained in the manual\n"
|
||||
<< endl
|
||||
<< " -autocode <0|1|2> Set automatic code vs. data determination in the disassembler\n"
|
||||
<< " -debuggerres <WxH> The resolution to use in debugger mode\n"
|
||||
<< " -break <address> Set a breakpoint at 'address'\n"
|
||||
<< " -debug Start in debugger mode\n"
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
// Copyright (C) 2002-2004 The ScummVM project
|
||||
//============================================================================
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "Dialog.hxx"
|
||||
|
@ -28,20 +30,22 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
EditTextWidget::EditTextWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int w, int h, const string& text)
|
||||
: EditableWidget(boss, font, x, y - 1, w, h + 2)
|
||||
: EditableWidget(boss, font, x, y - 1, w, h + 2),
|
||||
_editable(true),
|
||||
_changed(false)
|
||||
{
|
||||
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
|
||||
_type = kEditTextWidget;
|
||||
|
||||
_editable = true;
|
||||
startEditMode(); // We're always in edit mode
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void EditTextWidget::setEditString(const string& str)
|
||||
void EditTextWidget::setEditString(const string& str, bool changed)
|
||||
{
|
||||
EditableWidget::setEditString(str);
|
||||
_backupString = str;
|
||||
_changed = changed;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -74,6 +78,10 @@ void EditTextWidget::drawWidget(bool hilite)
|
|||
//cerr << "EditTextWidget::drawWidget\n";
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
|
||||
// Highlight changes
|
||||
if(_changed)
|
||||
s.fillRect(_x, _y, _w, _h, kDbgChangedColor);
|
||||
|
||||
// Draw a thin frame around us.
|
||||
s.hLine(_x, _y, _x + _w - 1, kColor);
|
||||
s.hLine(_x, _y + _h - 1, _x +_w - 1, kShadowColor);
|
||||
|
@ -83,7 +91,8 @@ void EditTextWidget::drawWidget(bool hilite)
|
|||
// Draw the text
|
||||
adjustOffset();
|
||||
s.drawString(_font, _editString, _x + 2, _y + 2, getEditRect().width(),
|
||||
_textcolor, kTextAlignLeft, -_editScrollOffset, false);
|
||||
!_changed ? _textcolor : kDbgChangedTextColor,
|
||||
kTextAlignLeft, -_editScrollOffset, false);
|
||||
|
||||
// Draw the caret
|
||||
drawCaret();
|
||||
|
|
|
@ -33,7 +33,7 @@ class EditTextWidget : public EditableWidget
|
|||
EditTextWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, int w, int h, const string& text);
|
||||
|
||||
void setEditString(const string& str);
|
||||
void setEditString(const string& str, bool changed = false);
|
||||
|
||||
virtual void handleMouseDown(int x, int y, int button, int clickCount);
|
||||
|
||||
|
@ -50,6 +50,7 @@ class EditTextWidget : public EditableWidget
|
|||
protected:
|
||||
string _backupString;
|
||||
int _editable;
|
||||
bool _changed;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,9 +54,9 @@ class EditableWidget : public Widget, public CommandSender
|
|||
virtual bool wantsFocus() { return _editable; }
|
||||
|
||||
protected:
|
||||
virtual void startEditMode() { setFlags(WIDGET_WANTS_RAWDATA); }
|
||||
virtual void endEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); }
|
||||
virtual void abortEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); }
|
||||
virtual void startEditMode() { setFlags(WIDGET_WANTS_RAWDATA); _editString = ""; }
|
||||
virtual void endEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); _editString = ""; }
|
||||
virtual void abortEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); _editString = ""; }
|
||||
|
||||
virtual GUI::Rect getEditRect() const = 0;
|
||||
virtual int getCaretOffset() const;
|
||||
|
|
|
@ -41,7 +41,6 @@ ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font,
|
|||
_highlightedItem(-1),
|
||||
_currentKeyDown(0),
|
||||
_editMode(false),
|
||||
_caretInverse(true),
|
||||
_quickSelect(quickSelect),
|
||||
_quickSelectTime(0)
|
||||
{
|
||||
|
|
|
@ -104,9 +104,7 @@ class ListWidget : public EditableWidget
|
|||
int _selectedItem;
|
||||
int _highlightedItem;
|
||||
int _currentKeyDown;
|
||||
|
||||
bool _editMode;
|
||||
bool _caretInverse;
|
||||
|
||||
ScrollBarWidget* _scrollBar;
|
||||
|
||||
|
|
Loading…
Reference in New Issue