Added debugging console/prompt commandline interface. It's still not

quite working correctly, but at least text appears when you type.

Changed the debugging TAB interface to use buttons instead.  It seems
this is a deficiency in the ScummVM GUI code, and I don't really want
to figure out how to fix it.  Of course, now the buttons have to be
embedded in each dialog box, somehow ...


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@469 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2005-06-07 01:14:39 +00:00
parent 6e074d8680
commit cf9f42b652
9 changed files with 887 additions and 175 deletions

View File

@ -13,7 +13,7 @@
## See the file "license" for information on usage and redistribution of
## this file, and for a DISCLAIMER OF ALL WARRANTIES.
##
## $Id: makefile,v 1.86 2005-06-03 17:52:04 stephena Exp $
## $Id: makefile,v 1.87 2005-06-07 01:14:38 stephena Exp $
##============================================================================
##============================================================================
@ -159,7 +159,8 @@ GUI_OBJS = StellaFont.o Menu.o Launcher.o Debugger.o \
Dialog.o DialogContainer.o OptionsDialog.o VideoDialog.o AudioDialog.o \
EventMappingDialog.o GameInfoDialog.o HelpDialog.o AboutDialog.o \
LauncherDialog.o LauncherOptionsDialog.o BrowserDialog.o GameList.o \
ProgressDialog.o DebuggerDialog.o
ProgressDialog.o \
DebuggerDialog.o PromptDialog.o
CORE_OBJS = Booster.o Cart.o Cart2K.o Cart3F.o Cart4K.o CartAR.o CartDPC.o \
CartE0.o CartE7.o CartF4.o CartF4SC.o CartF6.o CartF6SC.o \
@ -450,3 +451,6 @@ ProgressDialog.o: $(GUI)/ProgressDialog.cxx $(GUI)/ProgressDialog.hxx
DebuggerDialog.o: $(GUI)/DebuggerDialog.cxx $(GUI)/DebuggerDialog.hxx
$(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(GUI)/DebuggerDialog.cxx
PromptDialog.o: $(GUI)/PromptDialog.cxx $(GUI)/PromptDialog.hxx
$(CXX) -c $(FLAGS) $(OPTIONS) $(LDFLAGS) $(GUI)/PromptDialog.cxx

View File

@ -13,142 +13,72 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerDialog.cxx,v 1.1 2005-06-03 17:52:06 stephena Exp $
// $Id: DebuggerDialog.cxx,v 1.2 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
//============================================================================
#include "DialogContainer.hxx"
#include "BrowserDialog.hxx"
#include "PopUpWidget.hxx"
#include "TabWidget.hxx"
#include "FSNode.hxx"
#include "bspf.hxx"
#include "PromptDialog.hxx"
#include "DebuggerDialog.hxx"
enum {
kChooseRomDirCmd = 'roms', // rom select
kChooseSnapDirCmd = 'snps', // snap select
kRomDirChosenCmd = 'romc', // rom chosen
kSnapDirChosenCmd = 'snpc' // snap chosen
kPromptCmd = 'PRMT',
kCpuCmd = 'CPU ',
kRamCmd = 'RAM ',
kRomCmd = 'ROM ',
kTiaCmd = 'TIA ',
kCodeCmd = 'CODE'
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DebuggerDialog::DebuggerDialog(
OSystem* osystem, DialogContainer* parent,
int x, int y, int w, int h)
: Dialog(osystem, parent, x, y, w, h)
DebuggerDialog::DebuggerDialog(OSystem* osystem, DialogContainer* parent,
int x, int y, int w, int h)
: Dialog(osystem, parent, x, y, w, h),
myPromptDialog(NULL),
myCpuDialog(NULL),
myRamDialog(NULL),
myRomDialog(NULL),
myTiaDialog(NULL),
myCodeDialog(NULL)
{
const int vBorder = 4;
int yoffset;
const int border = 5;
const int space = 5;
const int width = 40;
int xpos = border;
// The tab widget
TabWidget* tab = new TabWidget(this, 0, vBorder, _w, _h);
// Add a row of buttons for the various debugger operations
new ButtonWidget(this, xpos, border, width, 16, "Prompt", kPromptCmd, 0);
xpos += space + width;
new ButtonWidget(this, xpos, border, width, 16, "CPU", kCpuCmd, 0);
xpos += space + width;
new ButtonWidget(this, xpos, border, width, 16, "RAM", kRamCmd, 0);
xpos += space + width;
new ButtonWidget(this, xpos, border, width, 16, "ROM", kRomCmd, 0);
xpos += space + width;
new ButtonWidget(this, xpos, border, width, 16, "TIA", kTiaCmd, 0);
xpos += space + width;
new ButtonWidget(this, xpos, border, width, 16, "Code", kCodeCmd, 0);
xpos += space + width;
// 1) The command prompt
tab->addTab("Prompt");
yoffset = vBorder;
// FIXME - add scrollable console/edittext window
// 2) The CPU contents
tab->addTab(" CPU ");
yoffset = vBorder;
// FIXME - add CPU registers
// 3) The RAM contents
tab->addTab(" RAM ");
yoffset = vBorder;
// FIXME - add 16x8 list of RAM contents
/*
// Snapshot path
new ButtonWidget(tab, 15, yoffset, kButtonWidth + 14, 16, "Path", kChooseSnapDirCmd, 0);
mySnapPath = new StaticTextWidget(tab, 5 + kButtonWidth + 30,
yoffset + 3, _w - (5 + kButtonWidth + 20) - 10,
kLineHeight, "", kTextAlignLeft);
yoffset += 22;
// Snapshot save name
mySnapTypePopup = new PopUpWidget(tab, 10, yoffset, 140, kLineHeight,
"Save snapshot as: ", 87, 0);
mySnapTypePopup->appendEntry("romname", 1);
mySnapTypePopup->appendEntry("md5sum", 2);
yoffset += 18;
// Snapshot single or multiple saves
mySnapSingleCheckbox = new CheckboxWidget(tab, 30, yoffset, 80, kLineHeight,
"Multiple snapshots");
*/
// 4) The ROM contents
tab->addTab(" ROM ");
yoffset = vBorder;
// FIXME - add ROM contents, somehow taking into account which bank is being
// viewed (maybe a button to switch banks??
// 5) The TIA contents
tab->addTab(" TIA ");
yoffset = vBorder;
// FIXME - TIA registers
// 6) The code listing
tab->addTab(" Code");
yoffset = vBorder;
// FIXME - Add code listing in assembly language
// Activate the first tab
tab->setActiveTab(0);
/*
// Create file browser dialog
int baseW = instance()->frameBuffer().baseWidth();
int baseH = instance()->frameBuffer().baseHeight();
myBrowser = new BrowserDialog(this, 60, 20, baseW - 120, baseH - 40);
*/
const int xoff = border;
const int yoff = border + 16 + 2;
// And create the debugger dialog boxes
myPromptDialog = new PromptDialog(osystem, parent, x + xoff, y + yoff,
w - xoff, h - yoff);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DebuggerDialog::~DebuggerDialog()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::loadConfig()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::saveConfig()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::openRomBrowser()
{
delete myPromptDialog;
/*
myBrowser->setTitle("Select ROM directory:");
myBrowser->setEmitSignal(kRomDirChosenCmd);
myBrowser->setStartPath(myRomPath->getLabel());
parent()->addDialog(myBrowser);
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::openSnapBrowser()
{
/*
myBrowser->setTitle("Select snapshot directory:");
myBrowser->setEmitSignal(kSnapDirChosenCmd);
myBrowser->setStartPath(mySnapPath->getLabel());
parent()->addDialog(myBrowser);
delete myCpuDialog;
delete myRamDialog;
delete myRomDialog;
delete myTiaDialog;
delete myCodeDialog;
*/
}
@ -157,32 +87,40 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, int data)
{
switch (cmd)
{
case kOKCmd:
saveConfig();
close();
case kPromptCmd:
parent()->reStack();
parent()->addDialog(myPromptDialog);
break;
case kChooseRomDirCmd:
openRomBrowser();
case kCpuCmd:
parent()->reStack();
// parent()->addDialog(myCpuDialog);
cerr << "kCpuCmd\n";
break;
case kChooseSnapDirCmd:
openSnapBrowser();
case kRamCmd:
parent()->reStack();
// parent()->addDialog(myRamDialog);
cerr << "kRamCmd\n";
break;
case kRomDirChosenCmd:
{
FilesystemNode dir(myBrowser->getResult());
myRomPath->setLabel(dir.path());
case kRomCmd:
parent()->reStack();
// parent()->addDialog(myRomDialog);
cerr << "kRomCmd\n";
break;
}
case kSnapDirChosenCmd:
{
FilesystemNode dir(myBrowser->getResult());
mySnapPath->setLabel(dir.path());
case kTiaCmd:
parent()->reStack();
// parent()->addDialog(myTiaDialog);
cerr << "kTiaCmd\n";
break;
case kCodeCmd:
parent()->reStack();
// parent()->addDialog(myCodeDialog);
cerr << "kCodeCmd\n";
break;
}
default:
Dialog::handleCommand(sender, cmd, data);

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DebuggerDialog.hxx,v 1.1 2005-06-03 17:52:06 stephena Exp $
// $Id: DebuggerDialog.hxx,v 1.2 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -24,10 +24,12 @@
class OSystem;
class DialogContainer;
class BrowserDialog;
class CheckboxWidget;
class PopUpWidget;
class StaticTextWidget;
class PromptDialog;
class CpuDialog;
class RamDialog;
class RomDialog;
class TiaDialog;
class CodeDialog;
#include "Dialog.hxx"
@ -38,25 +40,16 @@ class DebuggerDialog : public Dialog
int x, int y, int w, int h);
~DebuggerDialog();
virtual void loadConfig();
virtual void saveConfig();
virtual void handleCommand(CommandSender* sender, int cmd, int data);
protected:
BrowserDialog* myBrowser;
// Rom path controls
StaticTextWidget* myRomPath;
// Snapshot controls
StaticTextWidget* mySnapPath;
PopUpWidget* mySnapTypePopup;
CheckboxWidget* mySnapSingleCheckbox;
private:
void openRomBrowser();
void openSnapBrowser();
// The debugger dialogs
PromptDialog* myPromptDialog;
CpuDialog* myCpuDialog;
RamDialog* myRamDialog;
RomDialog* myRomDialog;
TiaDialog* myTiaDialog;
CodeDialog* myCodeDialog;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: GuiUtils.hxx,v 1.8 2005-05-16 00:02:32 stephena Exp $
// $Id: GuiUtils.hxx,v 1.9 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -29,7 +29,7 @@
Probably not very neat, but at least it works ...
@author Stephen Anthony
@version $Id: GuiUtils.hxx,v 1.8 2005-05-16 00:02:32 stephena Exp $
@version $Id: GuiUtils.hxx,v 1.9 2005-06-07 01:14:39 stephena Exp $
*/
#define kLineHeight 12
@ -74,6 +74,14 @@ static const string EmptyString("");
template<typename T> inline void SWAP(T &a, T &b) { T tmp = a; a = b; b = tmp; }
template<typename T> inline T ABS (T x) { return (x>=0) ? x : -x; }
#if !defined(MIN)
template<typename T> inline T MIN (T a, T b) { return (a<b) ? a : b; }
#endif
#if !defined(MAX)
template<typename T> inline T MAX (T a, T b) { return (a>b) ? a : b; }
#endif
#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: LauncherDialog.cxx,v 1.18 2005-05-26 18:56:58 stephena Exp $
// $Id: LauncherDialog.cxx,v 1.19 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -66,7 +66,7 @@ LauncherDialog::LauncherDialog(OSystem* osystem, DialogContainer* parent,
myRomCount = new StaticTextWidget(this, _w - 100, 8, 90, kLineHeight,
"", kTextAlignRight);
// Add three buttons at the bottom
// Add four buttons at the bottom
const int border = 10;
const int space = 8;
const int buttons = 4;

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: ListWidget.cxx,v 1.8 2005-05-13 18:28:05 stephena Exp $
// $Id: ListWidget.cxx,v 1.9 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -36,7 +36,7 @@ ListWidget::ListWidget(GuiObject* boss, int x, int y, int w, int h)
: Widget(boss, x, y, w - kScrollBarWidth, h),
CommandSender(boss)
{
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANT_TICKLE;
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
_type = kListWidget;
_numberingMode = kListNumberingOne;
_entriesPerPage = (_h - 2) / kLineHeight;
@ -133,18 +133,6 @@ void ListWidget::scrollBarRecalc()
_scrollBar->recalc();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ListWidget::handleTickle()
{
/*
uint32 time = g_system->getMillis();
if (_editMode && _caretTime < time) {
_caretTime = time + kCaretBlinkTime;
drawCaret(_caretVisible);
}
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ListWidget::handleMouseDown(int x, int y, int button, int clickCount)
{

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: ListWidget.hxx,v 1.3 2005-05-13 18:28:06 stephena Exp $
// $Id: ListWidget.hxx,v 1.4 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
@ -60,7 +60,6 @@ class ListWidget : public Widget, public CommandSender
void setNumberingMode(NumberingMode numberingMode) { _numberingMode = numberingMode; }
void scrollTo(int item);
virtual void handleTickle();
virtual void handleMouseDown(int x, int y, int button, int clickCount);
virtual void handleMouseUp(int x, int y, int button, int clickCount);
virtual void handleMouseWheel(int x, int y, int direction);

View File

@ -0,0 +1,649 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: PromptDialog.cxx,v 1.1 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
//============================================================================
#include "ScrollBarWidget.hxx"
#include "FrameBuffer.hxx"
#include "PromptDialog.hxx"
//#define kConsoleCharWidth (g_consolefont.getMaxCharWidth())
//#define kConsoleLineHeight (g_consolefont.getFontHeight() + 2)
#define kConsoleCharWidth (8)
#define kConsoleLineHeight (10 + 2)
#define PROMPT "> "
/* TODO:
* - it is very inefficient to redraw the full thingy when just one char is added/removed.
* Instead, we could just copy the GFX of the blank console (i.e. after the transparent
* background is drawn, before any text is drawn). Then using that, it becomes trivial
* to erase a single character, do scrolling etc.
* - a *lot* of others things, this code is in no way complete and heavily under progress
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PromptDialog::PromptDialog(OSystem* osystem, DialogContainer* parent,
int x, int y, int w, int h)
: Dialog(osystem, parent, x, y, w, h)
{
// Calculate depending values
_lineWidth = (_w - kScrollBarWidth - 2) / kConsoleCharWidth;
_linesPerPage = (_h - 2) / kConsoleLineHeight;
memset(_buffer, ' ', kBufferSize);
_linesInBuffer = kBufferSize / _lineWidth;
_currentPos = 0;
_scrollLine = _linesPerPage - 1;
_firstLineInBuffer = 0;
_caretVisible = true;//false;
_caretTime = 0;
_slideMode = kNoSlideMode;
_slideTime = 0;
// Add scrollbar
_scrollBar = new ScrollBarWidget(this, _w - kScrollBarWidth - 1, 0, kScrollBarWidth, _h);
_scrollBar->setTarget(this);
// Init callback
_callbackProc = 0;
_callbackRefCon = 0;
// Init History
_historyIndex = 0;
_historyLine = 0;
_historySize = 0;
for (int i = 0; i < kHistorySize; i++)
_history[i][0] = '\0';
_promptStartPos = _promptEndPos = -1;
// Display greetings & prompt
print("HELLO!!");//gScummVMFullVersion);
print("\nDebugger is ready\n");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PromptDialog::~PromptDialog()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::drawDialog()
{
FrameBuffer& fb = instance()->frameBuffer();
// Blend over the background
fb.blendRect(_x, _y, _w, _h, kBGColor, 2);
// Draw a border
fb.hLine(_x, _y + _h - 1, _x + _w - 1, kColor);
// Draw text
int start = _scrollLine - _linesPerPage + 1;
int y = _y + 2;
for (int line = 0; line < _linesPerPage; line++)
{
int x = _x + 1;
for (int column = 0; column < _lineWidth; column++) {
#if 0
int l = (start + line) % _linesInBuffer;
char c = buffer(l * _lineWidth + column);
#else
char c = buffer((start + line) * _lineWidth + column);
#endif
fb.drawChar(c, x, y, kTextColor);
x += kConsoleCharWidth;
}
y += kConsoleLineHeight;
}
// Draw the scrollbar
_scrollBar->draw();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::handleMouseWheel(int x, int y, int direction)
{
_scrollBar->handleMouseWheel(x, y, direction);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::handleKeyDown(int ascii, int keycode, int modifiers)
{
cerr << "PromptDialog::handleKeyDown\n";
int i;
if (_slideMode != kNoSlideMode)
return;
switch (keycode)
{
case '\n': // enter/return
case '\r':
{
if (_caretVisible)
drawCaret(true);
nextLine();
assert(_promptEndPos >= _promptStartPos);
int len = _promptEndPos - _promptStartPos;
bool keepRunning = true;
if (len > 0)
{
// We have to allocate the string buffer with new, since VC++ sadly does not
// comply to the C++ standard, so we can't use a dynamic sized stack array.
char *str = new char[len + 1];
// Copy the user input to str
for (i = 0; i < len; i++)
str[i] = buffer(_promptStartPos + i);
str[len] = '\0';
// Add the input to the history
addToHistory(str);
// Pass it to the input callback, if any
if (_callbackProc)
keepRunning = (*_callbackProc)(this, str, _callbackRefCon);
// Get rid of the string buffer
delete [] str;
}
print(PROMPT);
_promptStartPos = _promptEndPos = _currentPos;
draw();
instance()->frameBuffer().refresh();
break;
}
case 8: // backspace
if (_caretVisible)
drawCaret(true);
if (_currentPos > _promptStartPos)
{
_currentPos--;
killChar();
}
scrollToCurrent();
draw(); // FIXME - not nice to redraw the full console just for one char!
instance()->frameBuffer().refresh();
break;
case 9: // tab
{
if (_completionCallbackProc)
{
int len = _currentPos - _promptStartPos;
assert(len >= 0);
char *str = new char[len + 1];
// Copy the user input to str
for (i = 0; i < len; i++)
str[i] = buffer(_promptStartPos + i);
str[len] = '\0';
char *completion = 0;
if ((*_completionCallbackProc)(this, str, completion, _callbackRefCon))
{
if (_caretVisible)
drawCaret(true);
insertIntoPrompt(completion);
scrollToCurrent();
draw();
instance()->frameBuffer().refresh();
delete[] completion;
}
delete[] str;
}
break;
}
case 127:
killChar();
draw();
instance()->frameBuffer().refresh();
break;
case 256 + 24: // pageup
if (1) // FIXME - shift modifiers == OSystem::KBD_SHIFT)
{
_scrollLine -= _linesPerPage - 1;
if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
draw();
instance()->frameBuffer().refresh();
}
break;
case 256 + 25: // pagedown
if (1) // FIXME - shift modifiers == OSystem::KBD_SHIFT)
{
_scrollLine += _linesPerPage - 1;
if (_scrollLine > _promptEndPos / _lineWidth)
_scrollLine = _promptEndPos / _lineWidth;
updateScrollBuffer();
draw();
instance()->frameBuffer().refresh();
}
break;
case 256 + 22: // home
if (1) // FIXME - shift modifiers == OSystem::KBD_SHIFT)
{
_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
updateScrollBuffer();
}
else
_currentPos = _promptStartPos;
draw();
instance()->frameBuffer().refresh();
break;
case 256 + 23: // end
if (1) // FIXME - shift modifiers == OSystem::KBD_SHIFT)
{
_scrollLine = _promptEndPos / _lineWidth;
if (_scrollLine < _linesPerPage - 1)
_scrollLine = _linesPerPage - 1;
updateScrollBuffer();
}
else
_currentPos = _promptEndPos;
draw();
instance()->frameBuffer().refresh();
break;
case 273: // cursor up
historyScroll(+1);
break;
case 274: // cursor down
historyScroll(-1);
break;
case 275: // cursor right
if (_currentPos < _promptEndPos)
_currentPos++;
draw();
instance()->frameBuffer().refresh();
break;
case 276: // cursor left
if (_currentPos > _promptStartPos)
_currentPos--;
draw();
instance()->frameBuffer().refresh();
break;
default:
/* FIXME
} else if (modifiers == OSystem::KBD_CTRL) {
specialKeys(keycode);
*/
if (isprint((char)ascii))
{
for (i = _promptEndPos - 1; i >= _currentPos; i--)
buffer(i + 1) = buffer(i);
_promptEndPos++;
putchar((char)ascii);
scrollToCurrent();
}
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::insertIntoPrompt(const char* str)
{
unsigned int l = strlen(str);
for (int i = _promptEndPos - 1; i >= _currentPos; i--)
buffer(i + l) = buffer(i);
for (unsigned int j = 0; j < l; ++j)
{
_promptEndPos++;
putcharIntern(str[j]);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::handleCommand(CommandSender* sender, int cmd, int data)
{
switch (cmd)
{
case kSetPositionCmd:
int newPos = (int)data + _linesPerPage - 1 + _firstLineInBuffer;
if (newPos != _scrollLine)
{
_scrollLine = newPos;
draw();
instance()->frameBuffer().refresh();
}
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::specialKeys(int keycode)
{
/* FIXME - add UNIX style line editing
switch (keycode) {
case 'a':
_currentPos = _promptStartPos;
draw();
break;
case 'd':
if (_currentPos < _promptEndPos) {
killChar();
draw();
}
break;
case 'e':
_currentPos = _promptEndPos;
draw();
break;
case 'k':
killLine();
draw();
break;
case 'w':
killLastWord();
draw();
break;
}
*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::killChar()
{
for (int i = _currentPos; i < _promptEndPos; i++)
buffer(i) = buffer(i + 1);
buffer(_promptEndPos) = ' ';
_promptEndPos--;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::killLine()
{
for (int i = _currentPos; i < _promptEndPos; i++)
buffer(i) = ' ';
_promptEndPos = _currentPos;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::killLastWord()
{
int cnt = 0;
bool space = true;
while (_currentPos > _promptStartPos)
{
if (buffer(_currentPos - 1) == ' ')
{
if (!space)
break;
}
else
space = false;
_currentPos--;
cnt++;
}
for (int i = _currentPos; i < _promptEndPos; i++)
buffer(i) = buffer(i + cnt);
buffer(_promptEndPos) = ' ';
_promptEndPos -= cnt;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::addToHistory(const char *str)
{
strcpy(_history[_historyIndex], str);
_historyIndex = (_historyIndex + 1) % kHistorySize;
_historyLine = 0;
if (_historySize < kHistorySize)
_historySize++;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::historyScroll(int direction)
{
if (_historySize == 0)
return;
if (_historyLine == 0 && direction > 0)
{
int i;
for (i = 0; i < _promptEndPos - _promptStartPos; i++)
_history[_historyIndex][i] = buffer(_promptStartPos + i);
_history[_historyIndex][i] = '\0';
}
// Advance to the next line in the history
int line = _historyLine + direction;
if ((direction < 0 && line < 0) || (direction > 0 && line > _historySize))
return;
_historyLine = line;
// Hide caret if visible
if (_caretVisible)
drawCaret(true);
// Remove the current user text
_currentPos = _promptStartPos;
killLine();
// ... and ensure the prompt is visible
scrollToCurrent();
// Print the text from the history
int idx;
if (_historyLine > 0)
idx = (_historyIndex - _historyLine + _historySize) % _historySize;
else
idx = _historyIndex;
for (int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++)
putcharIntern(_history[idx][i]);
_promptEndPos = _currentPos;
// Ensure once more the caret is visible (in case of very long history entries)
scrollToCurrent();
draw();
instance()->frameBuffer().refresh();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::nextLine()
{
int line = _currentPos / _lineWidth;
if (line == _scrollLine)
_scrollLine++;
_currentPos = (line + 1) * _lineWidth;
updateScrollBuffer();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Call this (at least) when the current line changes or when a new line is added
void PromptDialog::updateScrollBuffer()
{
int lastchar = MAX(_promptEndPos, _currentPos);
int line = lastchar / _lineWidth;
int numlines = (line < _linesInBuffer) ? line + 1 : _linesInBuffer;
int firstline = line - numlines + 1;
if (firstline > _firstLineInBuffer)
{
// clear old line from buffer
for (int i = lastchar; i < (line+1) * _lineWidth; ++i)
buffer(i) = ' ';
_firstLineInBuffer = firstline;
}
_scrollBar->_numEntries = numlines;
_scrollBar->_currentPos = _scrollBar->_numEntries - (line - _scrollLine + _linesPerPage);
_scrollBar->_entriesPerPage = _linesPerPage;
_scrollBar->recalc();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int PromptDialog::printf(const char *format, ...)
{
va_list argptr;
va_start(argptr, format);
int count = this->vprintf(format, argptr);
va_end (argptr);
return count;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int PromptDialog::vprintf(const char *format, va_list argptr)
{
char buf[2048];
#if defined(WIN32)
int count = _vsnprintf(buf, sizeof(buf), format, argptr);
#else
int count = vsnprintf(buf, sizeof(buf), format, argptr);
#endif
print(buf);
return count;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::putchar(int c)
{
if (_caretVisible)
drawCaret(true);
putcharIntern(c);
draw(); // FIXME - not nice to redraw the full console just for one char!
instance()->frameBuffer().refresh();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::putcharIntern(int c)
{
if (c == '\n')
nextLine();
else
{
buffer(_currentPos) = (char)c;
_currentPos++;
if ((_scrollLine + 1) * _lineWidth == _currentPos)
{
_scrollLine++;
updateScrollBuffer();
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::print(const char *str)
{
if (_caretVisible)
drawCaret(true);
while (*str)
putcharIntern(*str++);
draw();
instance()->frameBuffer().refresh();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::drawCaret(bool erase)
{
FrameBuffer& fb = instance()->frameBuffer();
int line = _currentPos / _lineWidth;
int displayLine = line - _scrollLine + _linesPerPage - 1;
// Only draw caret if visible
if (!isVisible() || displayLine < 0 || displayLine >= _linesPerPage)
{
_caretVisible = false;
return;
}
int x = _x + 1 + (_currentPos % _lineWidth) * kConsoleCharWidth;
int y = _y + displayLine * kConsoleLineHeight;
char c = buffer(_currentPos);
if (erase)
{
fb.fillRect(x, y, kConsoleCharWidth, kConsoleLineHeight, kBGColor);
fb.drawChar(c, x, y + 2, kTextColor);
}
else
{
fb.fillRect(x, y, kConsoleCharWidth, kConsoleLineHeight, kTextColor);
fb.drawChar(c, x, y + 2, kBGColor);
}
//FIXMEg_gui.addDirtyRect(x, y, kConsoleCharWidth, kConsoleLineHeight);
fb.refresh();
_caretVisible = !erase;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PromptDialog::scrollToCurrent()
{
int line = _promptEndPos / _lineWidth;
if (line + _linesPerPage <= _scrollLine)
{
// TODO - this should only occur for loong edit lines, though
}
else if (line > _scrollLine)
{
_scrollLine = line;
updateScrollBuffer();
}
}

View File

@ -0,0 +1,133 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2005 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: PromptDialog.hxx,v 1.1 2005-06-07 01:14:39 stephena Exp $
//
// Based on code from ScummVM - Scumm Interpreter
// Copyright (C) 2002-2004 The ScummVM project
//============================================================================
#ifndef PROMPT_DIALOG_HXX
#define PROMPT_DIALOG_HXX
class CommandSender;
class DialogContainer;
class ScrollBarWidget;
#include <stdarg.h>
#include "Dialog.hxx"
enum {
kBufferSize = 32768,
kLineBufferSize = 256,
kHistorySize = 20
};
class PromptDialog : public Dialog
{
public:
PromptDialog(OSystem* osystem, DialogContainer* parent,
int x, int y, int w, int h);
virtual ~PromptDialog();
void handleMouseWheel(int x, int y, int direction);
void handleKeyDown(int ascii, int keycode, int modifiers);
void handleCommand(CommandSender* sender, int cmd, int data);
public:
int printf(const char *format, ...);
int vprintf(const char *format, va_list argptr);
#undef putchar
void putchar(int c);
typedef bool (*InputCallbackProc)(PromptDialog *console, const char *input, void *refCon);
typedef bool (*CompletionCallbackProc)(PromptDialog* console, const char *input, char*& completion, void *refCon);
void setInputCallback(InputCallbackProc proc, void *refCon) {
_callbackProc = proc;
_callbackRefCon = refCon;
}
void setCompletionCallback(CompletionCallbackProc proc, void *refCon) {
_completionCallbackProc = proc;
_completionCallbackRefCon = refCon;
}
protected:
inline char &buffer(int idx) { return _buffer[idx % kBufferSize]; }
void drawDialog();
void drawCaret(bool erase);
void putcharIntern(int c);
void insertIntoPrompt(const char *str);
void print(const char *str);
void updateScrollBuffer();
void scrollToCurrent();
// Line editing
void specialKeys(int keycode);
void nextLine();
void killChar();
void killLine();
void killLastWord();
// History
void addToHistory(const char *str);
void historyScroll(int direction);
protected:
char _buffer[kBufferSize];
int _linesInBuffer;
int _lineWidth;
int _linesPerPage;
int _currentPos;
int _scrollLine;
int _firstLineInBuffer;
int _promptStartPos;
int _promptEndPos;
bool _caretVisible;
int _caretTime;
enum SlideMode {
kNoSlideMode,
kUpSlideMode,
kDownSlideMode
};
SlideMode _slideMode;
int _slideTime;
ScrollBarWidget* _scrollBar;
// The _callbackProc is called whenver a data line is entered
//
InputCallbackProc _callbackProc;
void *_callbackRefCon;
// _completionCallbackProc is called when tab is pressed
CompletionCallbackProc _completionCallbackProc;
void *_completionCallbackRefCon;
char _history[kHistorySize][kLineBufferSize];
int _historySize;
int _historyIndex;
int _historyLine;
};
#endif