Merge branch 'release/6.0'
25
Changes.txt
|
@ -12,29 +12,29 @@
|
|||
Release History
|
||||
===========================================================================
|
||||
|
||||
5.1.3 to 5.2: (MMM d, 2018)
|
||||
5.1.3 to 6.0: (MMM d, 2018)
|
||||
|
||||
* New cycle exact audio core based on work by Chris Brenner (crispy); greatly
|
||||
improved audio emulation accuracy (i.e. E.T., Ms. Pacman)
|
||||
improved audio emulation accuracy (i.e. E.T., Ms. Pacman).
|
||||
|
||||
* Full rewrite of the audio subsystem; resample TIA output to target sample
|
||||
rate directly in Stella
|
||||
rate directly in Stella.
|
||||
|
||||
* Threading: decouple emulation from frame rendering
|
||||
* Threading: decouple emulation from frame rendering.
|
||||
|
||||
* Main loop rewritten; emulating speed and timing is now much more faithful
|
||||
(i.e. speed in Pick'n'Pile)
|
||||
(i.e. speed in Pick'n'Pile).
|
||||
|
||||
* Audio settings replaced with new audio.xxx settings
|
||||
* Audio settings replaced with new 'audio.xxx' settings.
|
||||
|
||||
* FPS setting replaced with speed setting for adjusting emulation speed
|
||||
* FPS setting replaced with speed setting for adjusting emulation speed.
|
||||
|
||||
* Extra functionality for Time Machine dialog (start/stop recording;
|
||||
minor fixes; TODO button and initial key repeats...)
|
||||
|
||||
* Fixes for collision corner cases (during HBlank)
|
||||
* Fixes for collision corner cases (during HBlank).
|
||||
|
||||
* UI modernization (new widget look, dialog titles added, dialogs refactored)
|
||||
* UI modernization (new widget look, dialog titles added, dialogs refactored).
|
||||
|
||||
* Changes in 'Game Properties' dialog
|
||||
- 'Default' button now affects only current tab like in all other dialogs.
|
||||
|
@ -46,8 +46,11 @@
|
|||
* The Linux builds now use the system-installed PNG and ZLIB libraries
|
||||
by default.
|
||||
|
||||
* When starting Stella for the first time, the first ROM selected will
|
||||
determine which path to use by default for subsequent runs.
|
||||
|
||||
* Fixed emulator crash when starting SaveKey ROMs from commandline with
|
||||
SaveKey messages enabled
|
||||
SaveKey messages enabled.
|
||||
|
||||
* Fixed missing TV format update in frame stats dialog when switching display
|
||||
type.
|
||||
|
@ -57,7 +60,7 @@
|
|||
* Updated included PNG library to latest stable version.
|
||||
|
||||
* For better compatibility, the Windows 32-bit version does not requires SSE2
|
||||
anymore
|
||||
anymore.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.0 KiB |
|
@ -10,7 +10,7 @@
|
|||
<br><br>
|
||||
<center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center>
|
||||
|
||||
<center><h4><b>Release 5.1.1</b></h4></center>
|
||||
<center><h4><b>Release 6.0</b></h4></center>
|
||||
<br><br>
|
||||
|
||||
<center><h2><b>User's Guide</b></h2></center>
|
||||
|
@ -61,7 +61,7 @@
|
|||
|
||||
<br><br><br>
|
||||
|
||||
<center><b>February 1999 - February 2018</b></center>
|
||||
<center><b>February 1999 - TODO 2018</b></center>
|
||||
<center><b>The Stella Team</b></center>
|
||||
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
|
||||
|
||||
|
@ -2736,8 +2736,8 @@
|
|||
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">CommandLine</a></th></tr>
|
||||
<tr><td>Save path</td><td>Specifies where to save snapshots</td><td>-snapsavedir</td></tr>
|
||||
<tr><td>Load path</td><td>Specifies where to load snapshots</td><td>-snaploaddir</td></tr>
|
||||
<tr><td>Save snapshots according to</td><td>Specifies how to name saved snapshots</td><td>-snapname</td></tr>
|
||||
<tr><td>Continuous snapshot interval</td><td>Interval (in seconds) between snapshots</td><td>-ssinterval</td></tr>
|
||||
<tr><td>Use actual ROM name</td><td>Use the actual ROM filename instead of the internal database name.</td><td>-snapname</td></tr>
|
||||
<tr><td>Overwrite existing files</td><td>Whether to overwrite old snapshots</td><td>-sssingle</td></tr>
|
||||
<tr><td>Ignore scaling (1x mode)</td><td>Save snapshot in 1x mode without scaling</td><td>-ss1x</td></tr>
|
||||
</table>
|
||||
|
|
|
@ -40,19 +40,19 @@ class FilesystemNodeFactory
|
|||
enum Type { SYSTEM, ZIP };
|
||||
|
||||
public:
|
||||
static AbstractFSNode* create(const string& path, Type type)
|
||||
static unique_ptr<AbstractFSNode> create(const string& path, Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SYSTEM:
|
||||
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
||||
return new FilesystemNodePOSIX(path);
|
||||
return make_unique<FilesystemNodePOSIX>(path);
|
||||
#elif defined(BSPF_WINDOWS)
|
||||
return new FilesystemNodeWINDOWS(path);
|
||||
return make_unique<FilesystemNodeWINDOWS>(path);
|
||||
#endif
|
||||
break;
|
||||
case ZIP:
|
||||
return new FilesystemNodeZIP(path);
|
||||
return make_unique<FilesystemNodeZIP>(path);
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -29,8 +29,6 @@ FilesystemNodeZIP::FilesystemNodeZIP()
|
|||
_isDirectory(false),
|
||||
_isFile(false)
|
||||
{
|
||||
// We need a name, else the node is invalid
|
||||
_realNode = shared_ptr<AbstractFSNode>(nullptr);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -92,9 +90,7 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
else
|
||||
_isDirectory = true;
|
||||
|
||||
AbstractFSNode* tmp =
|
||||
FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM);
|
||||
_realNode = shared_ptr<AbstractFSNode>(tmp);
|
||||
_realNode = FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM);
|
||||
|
||||
setFlags(_zipFile, _virtualPath, _realNode);
|
||||
}
|
||||
|
@ -102,7 +98,7 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeZIP::FilesystemNodeZIP(
|
||||
const string& zipfile, const string& virtualpath,
|
||||
shared_ptr<AbstractFSNode> realnode, bool isdir)
|
||||
AbstractFSNodePtr realnode, bool isdir)
|
||||
: _error(ZIPERR_NONE),
|
||||
_numFiles(0),
|
||||
_isDirectory(isdir),
|
||||
|
@ -114,7 +110,7 @@ FilesystemNodeZIP::FilesystemNodeZIP(
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FilesystemNodeZIP::setFlags(const string& zipfile,
|
||||
const string& virtualpath,
|
||||
shared_ptr<AbstractFSNode> realnode)
|
||||
AbstractFSNodePtr realnode)
|
||||
{
|
||||
_zipFile = zipfile;
|
||||
_virtualPath = virtualpath;
|
||||
|
@ -195,7 +191,7 @@ uInt32 FilesystemNodeZIP::read(BytePtr& image) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AbstractFSNode* FilesystemNodeZIP::getParent() const
|
||||
AbstractFSNodePtr FilesystemNodeZIP::getParent() const
|
||||
{
|
||||
if(_virtualPath == "")
|
||||
return _realNode ? _realNode->getParent() : nullptr;
|
||||
|
@ -203,7 +199,7 @@ AbstractFSNode* FilesystemNodeZIP::getParent() const
|
|||
const char* start = _path.c_str();
|
||||
const char* end = lastPathComponent(_path);
|
||||
|
||||
return new FilesystemNodeZIP(string(start, end - start - 1));
|
||||
return make_shared<FilesystemNodeZIP>(string(start, end - start - 1));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -61,16 +61,16 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
//////////////////////////////////////////////////////////
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const;
|
||||
AbstractFSNode* getParent() const;
|
||||
AbstractFSNodePtr getParent() const;
|
||||
|
||||
uInt32 read(BytePtr& image) const;
|
||||
|
||||
private:
|
||||
FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
shared_ptr<AbstractFSNode> realnode, bool isdir);
|
||||
AbstractFSNodePtr realnode, bool isdir);
|
||||
|
||||
void setFlags(const string& zipfile, const string& virtualpath,
|
||||
shared_ptr<AbstractFSNode> realnode);
|
||||
AbstractFSNodePtr realnode);
|
||||
|
||||
friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node)
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
ZIPERR_NO_ROMS
|
||||
};
|
||||
|
||||
shared_ptr<AbstractFSNode> _realNode;
|
||||
AbstractFSNodePtr _realNode;
|
||||
string _zipFile, _virtualPath;
|
||||
string _name, _path, _shortPath;
|
||||
zip_error _error;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#ifndef VERSION_HXX
|
||||
#define VERSION_HXX
|
||||
|
||||
#define STELLA_VERSION "5.2_soundtest-1"
|
||||
#define STELLA_BUILD "4138"
|
||||
#define STELLA_VERSION "6.0_pre1"
|
||||
#define STELLA_BUILD "4409"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@ FilesystemNode::FilesystemNode()
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNode::FilesystemNode(AbstractFSNode *realNode)
|
||||
FilesystemNode::FilesystemNode(AbstractFSNodePtr realNode)
|
||||
: _realNode(realNode)
|
||||
{
|
||||
}
|
||||
|
@ -38,15 +38,11 @@ FilesystemNode::FilesystemNode(AbstractFSNode *realNode)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNode::FilesystemNode(const string& p)
|
||||
{
|
||||
AbstractFSNode* tmp = nullptr;
|
||||
|
||||
// Is this potentially a ZIP archive?
|
||||
if(BSPF::containsIgnoreCase(p, ".zip"))
|
||||
tmp = FilesystemNodeFactory::create(p, FilesystemNodeFactory::ZIP);
|
||||
_realNode = FilesystemNodeFactory::create(p, FilesystemNodeFactory::ZIP);
|
||||
else
|
||||
tmp = FilesystemNodeFactory::create(p, FilesystemNodeFactory::SYSTEM);
|
||||
|
||||
_realNode = shared_ptr<AbstractFSNode>(tmp);
|
||||
_realNode = FilesystemNodeFactory::create(p, FilesystemNodeFactory::SYSTEM);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -132,7 +128,7 @@ FilesystemNode FilesystemNode::getParent() const
|
|||
if (_realNode == nullptr)
|
||||
return *this;
|
||||
|
||||
AbstractFSNode* node = _realNode->getParent();
|
||||
AbstractFSNodePtr node = _realNode->getParent();
|
||||
return node ? FilesystemNode(node) : *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
class FilesystemNode;
|
||||
class AbstractFSNode;
|
||||
using AbstractFSNodePtr = shared_ptr<AbstractFSNode>;
|
||||
|
||||
/**
|
||||
* List of multiple file system nodes. E.g. the contents of a given directory.
|
||||
|
@ -144,7 +145,7 @@ class FilesystemNode
|
|||
* @return true if successful, false otherwise (e.g. when the directory
|
||||
* does not exist).
|
||||
*/
|
||||
virtual bool getChildren(FSList &fslist, ListMode mode = kListDirectoriesOnly,
|
||||
virtual bool getChildren(FSList& fslist, ListMode mode = kListDirectoriesOnly,
|
||||
bool hidden = false) const;
|
||||
|
||||
/**
|
||||
|
@ -261,8 +262,8 @@ class FilesystemNode
|
|||
string getShortPathWithExt(const string& ext) const; // FIXME - dead code
|
||||
|
||||
private:
|
||||
shared_ptr<AbstractFSNode> _realNode;
|
||||
FilesystemNode(AbstractFSNode* realNode);
|
||||
AbstractFSNodePtr _realNode;
|
||||
FilesystemNode(AbstractFSNodePtr realNode);
|
||||
};
|
||||
|
||||
|
||||
|
@ -275,7 +276,7 @@ class FilesystemNode
|
|||
* the semantics.
|
||||
*/
|
||||
|
||||
using AbstractFSList = vector<AbstractFSNode*>;
|
||||
using AbstractFSList = vector<AbstractFSNodePtr>;
|
||||
|
||||
class AbstractFSNode
|
||||
{
|
||||
|
@ -403,7 +404,7 @@ class AbstractFSNode
|
|||
* The parent node of this directory.
|
||||
* The parent of the root is the root itself.
|
||||
*/
|
||||
virtual AbstractFSNode* getParent() const = 0;
|
||||
virtual AbstractFSNodePtr getParent() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font,
|
||||
const VariantList& combolist)
|
||||
: Dialog(boss->instance(), boss->parent(), font, ""),
|
||||
: Dialog(boss->instance(), boss->parent(), font, "Add..."),
|
||||
myComboEvent(Event::NoType)
|
||||
{
|
||||
const int lineHeight = font.getLineHeight(),
|
||||
|
@ -38,7 +38,7 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font,
|
|||
WidgetArray wid;
|
||||
|
||||
// Set real dimensions
|
||||
_w = 35 * fontWidth + 10;
|
||||
_w = 33 * fontWidth + 10*2;
|
||||
_h = 10 * (lineHeight + 4) + 10 + _th;
|
||||
xpos = 10;
|
||||
ypos = 10 + _th;
|
||||
|
@ -57,7 +57,6 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font,
|
|||
ypos += lineHeight + 4;
|
||||
};
|
||||
|
||||
xpos = 10;
|
||||
myEvents[0] = nullptr; ADD_EVENT_POPUP(0, "Event 1 ");
|
||||
myEvents[1] = nullptr; ADD_EVENT_POPUP(1, "Event 2 ");
|
||||
myEvents[2] = nullptr; ADD_EVENT_POPUP(2, "Event 3 ");
|
||||
|
|
|
@ -56,6 +56,7 @@ Dialog::Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font
|
|||
_okWidget(nullptr),
|
||||
_cancelWidget(nullptr),
|
||||
_visible(false),
|
||||
_onTop(true),
|
||||
_processCancel(false),
|
||||
_title(title),
|
||||
_th(0),
|
||||
|
@ -331,25 +332,25 @@ void Dialog::drawDialog()
|
|||
|
||||
cerr << COUNT++ << " Dialog::drawDialog()\n";
|
||||
// Dialog is still on top if e.g a ContextMenu is opened
|
||||
bool onTop = parent().myDialogStack.top() == this
|
||||
_onTop = parent().myDialogStack.top() == this
|
||||
|| (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
|
||||
&& !parent().myDialogStack.top()->hasTitle());
|
||||
|
||||
if(_flags & WIDGET_CLEARBG)
|
||||
{
|
||||
// cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl;
|
||||
s.fillRect(_x, _y + _th, _w, _h - _th, onTop ? kDlgColor : kBGColorLo);
|
||||
s.fillRect(_x, _y + _th, _w, _h - _th, _onTop ? kDlgColor : kBGColorLo);
|
||||
if(_th)
|
||||
{
|
||||
s.fillRect(_x, _y, _w, _th, onTop ? kColorTitleBar : kColorTitleBarLo);
|
||||
s.fillRect(_x, _y, _w, _th, _onTop ? kColorTitleBar : kColorTitleBarLo);
|
||||
s.drawString(_font, _title, _x + 10, _y + 2 + 1, _font.getStringWidth(_title),
|
||||
onTop ? kColorTitleText : kColorTitleTextLo);
|
||||
_onTop ? kColorTitleText : kColorTitleTextLo);
|
||||
}
|
||||
}
|
||||
else
|
||||
s.invalidate();
|
||||
if(_flags & WIDGET_BORDER)
|
||||
s.frameRect(_x, _y, _w, _h, onTop ? kColor : kShadowColor);
|
||||
if(_flags & WIDGET_BORDER) // currently only used by Dialog itself
|
||||
s.frameRect(_x, _y, _w, _h, _onTop ? kColor : kShadowColor);
|
||||
|
||||
// Make all child widget dirty
|
||||
Widget* w = _firstWidget;
|
||||
|
|
|
@ -55,6 +55,7 @@ class Dialog : public GuiObject
|
|||
void close();
|
||||
|
||||
bool isVisible() const override { return _visible; }
|
||||
bool isOnTop() { return _onTop; }
|
||||
|
||||
virtual void center();
|
||||
virtual void drawDialog();
|
||||
|
@ -152,6 +153,7 @@ class Dialog : public GuiObject
|
|||
Widget* _cancelWidget;
|
||||
|
||||
bool _visible;
|
||||
bool _onTop;
|
||||
bool _processCancel;
|
||||
string _title;
|
||||
int _th;
|
||||
|
|
|
@ -28,7 +28,7 @@ EditTextWidget::EditTextWidget(GuiObject* boss, const GUI::Font& font,
|
|||
_changed(false)
|
||||
{
|
||||
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
|
||||
|
||||
|
||||
startEditMode(); // We're always in edit mode
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,10 @@ void EditTextWidget::drawWidget(bool hilite)
|
|||
if(_changed)
|
||||
s.fillRect(_x, _y, _w, _h, kDbgChangedColor);
|
||||
else if(!isEditable())
|
||||
s.fillRect(_x, _y, _w, _h, kDlgColor);
|
||||
{
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
s.fillRect(_x, _y, _w, _h, onTop ? kDlgColor : kBGColorLo);
|
||||
}
|
||||
|
||||
// Draw a thin frame around us.
|
||||
s.frameRect(_x, _y, _w, _h, hilite && isEditable() && isEnabled() ? kWidColorHi : kColor);
|
||||
|
|
|
@ -39,6 +39,7 @@ EditableWidget::EditableWidget(GuiObject* boss, const GUI::Font& font,
|
|||
|
||||
_bgcolor = kWidColor;
|
||||
_bgcolorhi = kWidColor;
|
||||
_bgcolorlo = kDlgColor;
|
||||
_textcolor = kTextColor;
|
||||
_textcolorhi = kTextColor;
|
||||
|
||||
|
|
|
@ -57,17 +57,19 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent,
|
|||
const string ELLIPSIS = "\x1d";
|
||||
const GUI::Font& font = instance().frameBuffer().launcherFont();
|
||||
|
||||
const int HBORDER = 10;
|
||||
const int BUTTON_GAP = 8;
|
||||
const int fontWidth = font.getMaxCharWidth(),
|
||||
fontHeight = font.getFontHeight(),
|
||||
lineHeight = font.getLineHeight(),
|
||||
bwidth = (_w - 2 * 10 - 8 * (4 - 1)) / 4,
|
||||
bwidth = (_w - 2 * HBORDER - BUTTON_GAP * (4 - 1)),
|
||||
bheight = lineHeight + 4;
|
||||
int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0;
|
||||
int xpos, ypos = 0, lwidth = 0, lwidth2 = 0;
|
||||
WidgetArray wid;
|
||||
|
||||
// Show game name
|
||||
lwidth = font.getStringWidth("Select a ROM from the list" + ELLIPSIS);
|
||||
xpos += 10; ypos += 8;
|
||||
xpos = HBORDER; ypos += 8;
|
||||
new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight,
|
||||
"Select a ROM from the list" + ELLIPSIS);
|
||||
|
||||
|
@ -131,35 +133,35 @@ LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent,
|
|||
// Add four buttons at the bottom
|
||||
xpos = 10; ypos += myDir->getHeight() + 8;
|
||||
#ifndef BSPF_MAC_OSX
|
||||
myStartButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight,
|
||||
"Select", kLoadROMCmd);
|
||||
wid.push_back(myStartButton);
|
||||
xpos += bwidth + 8;
|
||||
myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
"Go Up", kPrevDirCmd);
|
||||
xpos += (bwidth + 0) / 4 + BUTTON_GAP;
|
||||
myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight,
|
||||
"Go Up", kPrevDirCmd);
|
||||
wid.push_back(myPrevDirButton);
|
||||
xpos += bwidth + 8;
|
||||
myOptionsButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
xpos += (bwidth + 1) / 4 + BUTTON_GAP;
|
||||
myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 4, bheight,
|
||||
"Options" + ELLIPSIS, kOptionsCmd);
|
||||
wid.push_back(myOptionsButton);
|
||||
xpos += bwidth + 8;
|
||||
myQuitButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
xpos += (bwidth + 2) / 4 + BUTTON_GAP;
|
||||
myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight,
|
||||
"Quit", kQuitCmd);
|
||||
wid.push_back(myQuitButton);
|
||||
#else
|
||||
myQuitButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
myQuitButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 0) / 4, bheight,
|
||||
"Quit", kQuitCmd);
|
||||
wid.push_back(myQuitButton);
|
||||
xpos += bwidth + 8;
|
||||
myOptionsButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
xpos += (bwidth + 0) / 4 + BUTTON_GAP;
|
||||
myOptionsButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 1) / 4, bheight,
|
||||
"Options" + ELLIPSIS, kOptionsCmd);
|
||||
wid.push_back(myOptionsButton);
|
||||
xpos += bwidth + 8;
|
||||
myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
xpos += (bwidth + 1) / 4 + BUTTON_GAP;
|
||||
myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 2) / 4, bheight,
|
||||
"Go Up", kPrevDirCmd);
|
||||
wid.push_back(myPrevDirButton);
|
||||
xpos += bwidth + 8;
|
||||
myStartButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight,
|
||||
xpos += (bwidth + 2) / 4 + BUTTON_GAP;
|
||||
myStartButton = new ButtonWidget(this, font, xpos, ypos, (bwidth + 3) / 4, bheight,
|
||||
"Select", kLoadROMCmd);
|
||||
wid.push_back(myStartButton);
|
||||
#endif
|
||||
|
@ -214,31 +216,12 @@ const string& LauncherDialog::selectedRomMD5()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void LauncherDialog::loadConfig()
|
||||
{
|
||||
// Should we use a temporary directory specified on the commandline, or the
|
||||
// default one specified by the settings?
|
||||
const string& tmpromdir = instance().settings().getString("tmpromdir");
|
||||
const string& romdir = tmpromdir != "" ? tmpromdir :
|
||||
instance().settings().getString("romdir");
|
||||
|
||||
// When romdir hasn't been set, it probably indicates that this is the first
|
||||
// time running Stella; in this case, we should prompt the user
|
||||
if(romdir == "")
|
||||
{
|
||||
if(!myFirstRunMsg)
|
||||
{
|
||||
StringList msg;
|
||||
msg.push_back("This seems to be your first time running Stella.");
|
||||
msg.push_back("Before you can start a game, you need to");
|
||||
msg.push_back("specify where your ROMs are located.");
|
||||
msg.push_back("");
|
||||
msg.push_back("Click 'Default' to select a default ROM directory,");
|
||||
msg.push_back("or 'Browse' to browse the filesystem manually.");
|
||||
myFirstRunMsg = make_unique<GUI::MessageBox>
|
||||
(this, instance().frameBuffer().font(),
|
||||
msg, _w, _h, kFirstRunMsgChosenCmd,
|
||||
"Default", "Browse", "ROM directory");
|
||||
}
|
||||
myFirstRunMsg->show();
|
||||
}
|
||||
|
||||
// Assume that if the list is empty, this is the first time that loadConfig()
|
||||
// has been called (and we should reload the list)
|
||||
if(myList->getList().empty())
|
||||
|
@ -486,7 +469,13 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
const string& result =
|
||||
instance().createConsole(romnode, myGameList->md5(item));
|
||||
if(result == EmptyString)
|
||||
{
|
||||
instance().settings().setValue("lastrom", myList->getSelectedString());
|
||||
|
||||
// If romdir has never been set, set it now based on the selected rom
|
||||
if(instance().settings().getString("romdir") == EmptyString)
|
||||
instance().settings().setValue("romdir", romnode.getParent().getShortPath());
|
||||
}
|
||||
else
|
||||
instance().frameBuffer().showMessage(result, MessagePosition::MiddleCenter, true);
|
||||
}
|
||||
|
@ -513,20 +502,6 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
instance().eventHandler().quit();
|
||||
break;
|
||||
|
||||
case kFirstRunMsgChosenCmd:
|
||||
// Show a file browser, starting from the users' home directory
|
||||
if(!myRomDir)
|
||||
myRomDir = make_unique<BrowserDialog>(this, instance().frameBuffer().font(),
|
||||
_w, _h, "Select ROM directory");
|
||||
myRomDir->show("~", BrowserDialog::Directories, kStartupRomDirChosenCmd);
|
||||
break;
|
||||
|
||||
case kStartupRomDirChosenCmd:
|
||||
{
|
||||
FilesystemNode dir(myRomDir->getResult());
|
||||
instance().settings().setValue("romdir", dir.getShortPath());
|
||||
[[fallthrough]];
|
||||
}
|
||||
case kRomDirChosenCmd:
|
||||
myCurrentNode = FilesystemNode(instance().settings().getString("romdir"));
|
||||
if(!(myCurrentNode.exists() && myCurrentNode.isDirectory()))
|
||||
|
|
|
@ -48,7 +48,7 @@ class LauncherDialog : public Dialog
|
|||
// These must be accessible from dialogs created by this class
|
||||
enum {
|
||||
kLoadROMCmd = 'STRT', // load currently selected ROM
|
||||
kRomDirChosenCmd = 'romc', // rom chosen
|
||||
kRomDirChosenCmd = 'romc', // rom dir chosen
|
||||
kReloadRomDirCmd = 'rdrl', // reload the current listing
|
||||
kReloadFiltersCmd = 'rlfl' // reload filtering options and current listing
|
||||
};
|
||||
|
@ -98,7 +98,6 @@ class LauncherDialog : public Dialog
|
|||
unique_ptr<GlobalPropsDialog> myGlobalProps;
|
||||
unique_ptr<LauncherFilterDialog> myFilters;
|
||||
unique_ptr<BrowserDialog> myRomDir;
|
||||
unique_ptr<GUI::MessageBox> myFirstRunMsg;
|
||||
|
||||
ButtonWidget* myStartButton;
|
||||
ButtonWidget* myPrevDirButton;
|
||||
|
@ -122,10 +121,7 @@ class LauncherDialog : public Dialog
|
|||
enum {
|
||||
kPrevDirCmd = 'PRVD',
|
||||
kOptionsCmd = 'OPTI',
|
||||
kQuitCmd = 'QUIT',
|
||||
|
||||
kFirstRunMsgChosenCmd = 'frmc',
|
||||
kStartupRomDirChosenCmd = 'rmsc'
|
||||
kQuitCmd = 'QUIT'
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -39,7 +39,8 @@ RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font,
|
|||
GUI::Size(320, TIAConstants::maxViewableHeight))
|
||||
{
|
||||
_flags = WIDGET_ENABLED;
|
||||
_bgcolor = _bgcolorhi = kWidColor;
|
||||
_bgcolor = kDlgColor;
|
||||
_bgcolorlo = kBGColorLo;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -139,10 +140,11 @@ void RomInfoWidget::parseProperties()
|
|||
void RomInfoWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& s = dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
const int yoff = myAvail.h + 10;
|
||||
|
||||
s.fillRect(_x+2, _y+2, _w-4, _h-4, kDlgColor);
|
||||
s.fillRect(_x+2, _y+2, _w-4, _h-4, onTop ? _bgcolor : _bgcolorlo);
|
||||
s.frameRect(_x, _y, _w, _h, kColor);
|
||||
s.frameRect(_x, _y+yoff, _w, _h-yoff, kColor);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ StringListWidget::StringListWidget(GuiObject* boss, const GUI::Font& font,
|
|||
boss->instance().settings().getInt("listdelay") >= 300),
|
||||
_hilite(hilite)
|
||||
{
|
||||
_bgcolorlo = kDlgColor;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -77,7 +78,10 @@ void StringListWidget::drawWidget(bool hilite)
|
|||
textColor = kTextColorInv;
|
||||
}
|
||||
else
|
||||
s.frameRect(_x + 1, _y + 1 + _fontHeight * i, _w - 1, _fontHeight, kWidColorHi);
|
||||
{
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
s.frameRect(_x + 1, _y + 1 + _fontHeight * i, _w - 1, _fontHeight, onTop ? kWidColorHi : kBGColorLo);
|
||||
}
|
||||
}
|
||||
|
||||
GUI::Rect r(getEditRect());
|
||||
|
|
|
@ -262,6 +262,7 @@ void TabWidget::drawWidget(bool hilite)
|
|||
Widget::setDirtyInChain(_tabs[_activeTab].firstWidget);
|
||||
|
||||
FBSurface& s = dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
// Iterate over all tabs and draw them
|
||||
int i, x = _x + kTabLeftOffset;
|
||||
|
@ -269,25 +270,27 @@ void TabWidget::drawWidget(bool hilite)
|
|||
{
|
||||
uInt32 fontcolor = _tabs[i].enabled ? kTextColor : kColor;
|
||||
int yOffset = (i == _activeTab) ? 0 : 1;
|
||||
s.fillRect(x, _y + 1, _tabWidth, _tabHeight - 1, (i == _activeTab)
|
||||
? kDlgColor : kBGColorHi); // ? kWidColor : kDlgColor
|
||||
s.fillRect(x, _y + 1, _tabWidth, _tabHeight - 1,
|
||||
(i == _activeTab)
|
||||
? onTop ? kDlgColor : kBGColorLo
|
||||
: onTop ? kBGColorHi : kDlgColor); // ? kWidColor : kDlgColor
|
||||
s.drawString(_font, _tabs[i].title, x + kTabPadding + yOffset,
|
||||
_y + yOffset + (_tabHeight - _fontHeight - 1),
|
||||
_tabWidth - 2 * kTabPadding, fontcolor, TextAlign::Center);
|
||||
if(i == _activeTab)
|
||||
{
|
||||
s.hLine(x, _y, x + _tabWidth - 1, kWidColor);
|
||||
s.vLine(x + _tabWidth, _y + 1, _y + _tabHeight - 1, kBGColorLo);
|
||||
s.hLine(x, _y, x + _tabWidth - 1, onTop ? kWidColor : kDlgColor);
|
||||
s.vLine(x + _tabWidth, _y + 1, _y + _tabHeight - 1, onTop ? kBGColorLo : kColor);
|
||||
}
|
||||
else
|
||||
s.hLine(x, _y + _tabHeight, x + _tabWidth, kWidColor);
|
||||
s.hLine(x, _y + _tabHeight, x + _tabWidth, onTop ? kWidColor : kDlgColor);
|
||||
|
||||
x += _tabWidth + kTabSpacing;
|
||||
}
|
||||
|
||||
// fill empty right space
|
||||
s.hLine(x - kTabSpacing + 1, _y + _tabHeight, _x + _w - 1, kWidColor);
|
||||
s.hLine(_x, _y + _h - 1, _x + _w - 1, kBGColorLo);
|
||||
s.hLine(x - kTabSpacing + 1, _y + _tabHeight, _x + _w - 1, onTop ? kWidColor : kDlgColor);
|
||||
s.hLine(_x, _y + _h - 1, _x + _w - 1, onTop ? kBGColorLo : kColor);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -38,8 +38,10 @@ Widget::Widget(GuiObject* boss, const GUI::Font& font,
|
|||
_hasFocus(false),
|
||||
_bgcolor(kWidColor),
|
||||
_bgcolorhi(kWidColor),
|
||||
_bgcolorlo(kBGColorLo),
|
||||
_textcolor(kTextColor),
|
||||
_textcolorhi(kTextColorHi),
|
||||
_textcolorlo(kBGColorLo),
|
||||
_shadowcolor(kShadowColor)
|
||||
{
|
||||
// Insert into the widget list of the boss
|
||||
|
@ -77,7 +79,9 @@ void Widget::draw()
|
|||
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
|
||||
bool hasBorder = _flags & WIDGET_BORDER;
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
bool hasBorder = _flags & WIDGET_BORDER; // currently only used by Dialog widget
|
||||
int oldX = _x, oldY = _y;
|
||||
|
||||
// Account for our relative position in the dialog
|
||||
|
@ -92,13 +96,13 @@ void Widget::draw()
|
|||
{
|
||||
x++; y++; w-=2; h-=2;
|
||||
}
|
||||
s.fillRect(x, y, w, h, (_flags & WIDGET_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor);
|
||||
s.fillRect(x, y, w, h, !onTop ? _bgcolorlo : (_flags & WIDGET_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor);
|
||||
}
|
||||
|
||||
// Draw border
|
||||
if(hasBorder)
|
||||
{
|
||||
s.frameRect(_x, _y, _w, _h, (_flags & WIDGET_HILITED) && isEnabled() ? kWidColorHi : kColor);
|
||||
s.frameRect(_x, _y, _w, _h, !onTop ? kColor : (_flags & WIDGET_HILITED) && isEnabled() ? kWidColorHi : kColor);
|
||||
_x += 4;
|
||||
_y += 4;
|
||||
_w -= 8;
|
||||
|
@ -203,6 +207,8 @@ Widget* Widget::setFocusForChain(GuiObject* boss, WidgetArray& arr,
|
|||
FBSurface& s = boss->dialog().surface();
|
||||
int size = int(arr.size()), pos = -1;
|
||||
Widget* tmp;
|
||||
bool onTop = boss->dialog().isOnTop();
|
||||
|
||||
for(int i = 0; i < size; ++i)
|
||||
{
|
||||
tmp = arr[i];
|
||||
|
@ -226,7 +232,7 @@ Widget* Widget::setFocusForChain(GuiObject* boss, WidgetArray& arr,
|
|||
else
|
||||
tmp->_hasFocus = false;
|
||||
|
||||
s.frameRect(x, y, w, h, kDlgColor);
|
||||
s.frameRect(x, y, w, h, onTop ? kDlgColor : kBGColorLo);
|
||||
|
||||
tmp->setDirty();
|
||||
}
|
||||
|
@ -279,7 +285,8 @@ Widget* Widget::setFocusForChain(GuiObject* boss, WidgetArray& arr,
|
|||
else
|
||||
tmp->_hasFocus = true;
|
||||
|
||||
s.frameRect(x, y, w, h, kWidFrameColor, FrameStyle::Dashed);
|
||||
if (onTop)
|
||||
s.frameRect(x, y, w, h, kWidFrameColor, FrameStyle::Dashed);
|
||||
|
||||
tmp->setDirty();
|
||||
|
||||
|
@ -368,8 +375,10 @@ ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|||
_flags = WIDGET_ENABLED | WIDGET_CLEARBG;
|
||||
_bgcolor = kBtnColor;
|
||||
_bgcolorhi = kBtnColorHi;
|
||||
_bgcolorlo = kColor;
|
||||
_textcolor = kBtnTextColor;
|
||||
_textcolorhi = kBtnTextColorHi;
|
||||
_textcolorlo = kBGColorLo;
|
||||
|
||||
_editable = false;
|
||||
}
|
||||
|
@ -457,16 +466,17 @@ void ButtonWidget::setBitmap(uInt32* bitmap, int bmw, int bmh)
|
|||
void ButtonWidget::drawWidget(bool hilite)
|
||||
{
|
||||
FBSurface& s = _boss->dialog().surface();
|
||||
bool onTop = _boss->dialog().isOnTop();
|
||||
|
||||
s.frameRect(_x, _y, _w, _h, hilite && isEnabled() ? kBtnBorderColorHi : kBtnBorderColor);
|
||||
s.frameRect(_x, _y, _w, _h, !onTop ? kShadowColor : hilite && isEnabled() ? kBtnBorderColorHi : kBtnBorderColor);
|
||||
|
||||
if (!_useBitmap)
|
||||
s.drawString(_font, _label, _x, _y + (_h - _fontHeight)/2 + 1, _w,
|
||||
!isEnabled() ? /*hilite ? uInt32(kColor) :*/ uInt32(kBGColorLo) :
|
||||
!(isEnabled() && onTop) ? _textcolorlo :
|
||||
hilite ? _textcolorhi : _textcolor, _align);
|
||||
else
|
||||
s.drawBitmap(_bitmap, _x + (_w - _bmw) / 2, _y + (_h - _bmh) / 2,
|
||||
!isEnabled() ? /*hilite ? uInt32(kColor) :*/ uInt32(kBGColorLo) :
|
||||
!(isEnabled() && onTop) ? _textcolorlo :
|
||||
hilite ? _textcolorhi : _textcolor,
|
||||
_bmw, _bmh);
|
||||
|
||||
|
|
|
@ -142,8 +142,10 @@ class Widget : public GuiObject
|
|||
int _fontHeight;
|
||||
uInt32 _bgcolor;
|
||||
uInt32 _bgcolorhi;
|
||||
uInt32 _bgcolorlo;
|
||||
uInt32 _textcolor;
|
||||
uInt32 _textcolorhi;
|
||||
uInt32 _textcolorlo;
|
||||
uInt32 _shadowcolor;
|
||||
|
||||
public:
|
||||
|
|
|
@ -97,12 +97,11 @@ bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode,
|
|||
assert(_isDirectory);
|
||||
|
||||
DIR* dirp = opendir(_path.c_str());
|
||||
struct dirent* dp;
|
||||
|
||||
if (dirp == nullptr)
|
||||
return false;
|
||||
|
||||
// loop over dir entries using readdir
|
||||
// Loop over dir entries using readdir
|
||||
struct dirent* dp;
|
||||
while ((dp = readdir(dirp)) != nullptr)
|
||||
{
|
||||
// Skip 'invisible' files if necessary
|
||||
|
@ -137,7 +136,6 @@ bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode,
|
|||
}
|
||||
else
|
||||
{
|
||||
entry._isValid = (dp->d_type == DT_DIR) || (dp->d_type == DT_REG) || (dp->d_type == DT_LNK);
|
||||
if (dp->d_type == DT_LNK)
|
||||
{
|
||||
struct stat st;
|
||||
|
@ -157,6 +155,8 @@ bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode,
|
|||
|
||||
if (entry._isDirectory)
|
||||
entry._path += "/";
|
||||
|
||||
entry._isValid = entry._isDirectory || entry._isFile;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -226,7 +226,7 @@ bool FilesystemNodePOSIX::rename(const string& newfile)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AbstractFSNode* FilesystemNodePOSIX::getParent() const
|
||||
AbstractFSNodePtr FilesystemNodePOSIX::getParent() const
|
||||
{
|
||||
if (_path == "/")
|
||||
return nullptr;
|
||||
|
@ -234,5 +234,5 @@ AbstractFSNode* FilesystemNodePOSIX::getParent() const
|
|||
const char* start = _path.c_str();
|
||||
const char* end = lastPathComponent(_path);
|
||||
|
||||
return new FilesystemNodePOSIX(string(start, size_t(end - start)));
|
||||
return make_unique<FilesystemNodePOSIX>(string(start, size_t(end - start)));
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ class FilesystemNodePOSIX : public AbstractFSNode
|
|||
bool rename(const string& newfile) override;
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode* getParent() const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
protected:
|
||||
string _path;
|
||||
|
|
|
@ -296,7 +296,7 @@ bool FilesystemNodeWINDOWS::rename(const string& newfile)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AbstractFSNode* FilesystemNodeWINDOWS::getParent() const
|
||||
AbstractFSNodePtr FilesystemNodeWINDOWS::getParent() const
|
||||
{
|
||||
if(_isPseudoRoot)
|
||||
return nullptr;
|
||||
|
@ -306,8 +306,8 @@ AbstractFSNode* FilesystemNodeWINDOWS::getParent() const
|
|||
const char* start = _path.c_str();
|
||||
const char* end = lastPathComponent(_path);
|
||||
|
||||
return new FilesystemNodeWINDOWS(string(start, size_t(end - start)));
|
||||
return make_shared<FilesystemNodeWINDOWS>(string(start, size_t(end - start)));
|
||||
}
|
||||
else
|
||||
return new FilesystemNodeWINDOWS();
|
||||
return make_shared<FilesystemNodeWINDOWS>();
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class FilesystemNodeWINDOWS : public AbstractFSNode
|
|||
bool rename(const string& newfile) override;
|
||||
|
||||
bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode* getParent() const override;
|
||||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
protected:
|
||||
string _displayName;
|
||||
|
|