Merge remote-tracking branch 'remotes/origin/master' into feature/dbg-save-as-dialog

This commit is contained in:
thrust26 2020-12-23 17:12:07 +01:00
commit 59311aa589
285 changed files with 11355 additions and 5471 deletions

10
.gitignore vendored
View File

@ -11,11 +11,12 @@ out
out.pgo
out.pgen
stella
stella-pgo
stella-pgo-generate
stella-pgo
stella-pgo-generate
*.diff
project.xcworkspace/
xcuserdata/
.DS_Store
build/
src/macosx/M6502.ins
*.dSYM
@ -33,4 +34,7 @@ src/**/*.vspx
src/**/**.pdb
Stella.xcscheme
src/tools/fonts/*
*.sym
a.out
*.json
*.sqlite3

View File

@ -1,6 +1,7 @@
.core-defs:
variables:
JNI_PATH: src/libretro
MAKEFILE_PATH: src/libretro
CORENAME: stella
include:
@ -23,46 +24,37 @@ stages:
#Desktop
libretro-build-linux-x64:
extends:
- .core-defs
- .libretro-linux-x64-make-default
variables:
MAKEFILE_PATH: src/libretro
MAKEFILE: Makefile
- .core-defs
libretro-build-windows-x64:
extends:
- .core-defs
- .libretro-windows-x64-mingw-make-default
variables:
MAKEFILE_PATH: src/libretro
MAKEFILE: Makefile
- .core-defs
# Android
android-armeabi-v7a:
extends:
- .core-defs
- .libretro-android-jni-armeabi-v7a
- .core-defs
android-arm64-v8a:
extends:
- .core-defs
- .libretro-android-jni-arm64-v8a
- .core-defs
android-x86_64:
extends:
- .core-defs
- .libretro-android-jni-x86_64
- .core-defs
android-x86:
extends:
- .core-defs
- .libretro-android-jni-x86
- .core-defs
# Static
libretro-build-libnx-aarch64:
extends:
- .core-defs
- .libretro-libnx-static-retroarch-master
variables:
MAKEFILE_PATH: src/libretro
MAKEFILE: Makefile
- .core-defs

View File

@ -14,23 +14,35 @@
6.4 to 6.5 (December XX, 2020)
* Enhanced cut/copy/paste for text editing. (TODO: PromptWidget)
* Added high scores saving.
* Added undo and redo to text editing. (TODO: PromptWidget)
* Improved text editing functionality (except PromptWidget):
- Enhanced selection and cut/copy/paste from keyboard.
- Added undo and redo support.
- Added mouse support (selection, cut/copy/paste).
- All actions have keyboard shortcuts.
* Added wildcard support to launcher dialog filter.
* Added option to search subdirectories in launcher.
* Various improvements to the ROM launcher:
- Added wildcard support to the dialog filter
- Added option to search subdirectories
* Added static tooltips to some UI items.
* Added dynamic tooltips to most debugger items.
* Added sound to Time Machine playback.
* Extended global hotkeys for input devices & ports settings.
* Increased sample size for CDFJ+.
* Fixed autofire bug for trackball controllers.
* Codebase now uses C++17 features.
* Fixed Stelladaptor/2600'daptor devices sometimes not being assigned
correct default mappings.
* Codebase now uses C++17 features, which means a minimum of gcc7
or clang5 for Linux/Mac, and Visual Studio 2019 for Windows.
-Have fun!

4
configure vendored
View File

@ -580,10 +580,6 @@ else
darwin*)
DEFINES="$DEFINES -DUNIX -DDARWIN"
_host_os=darwin
if test "$have_clang" = yes; then
CXXFLAGS="$CXXFLAGS -Wno-documentation-unknown-command -Wno-documentation-pedantic -Wno-poison-system-directories"
CXXFLAGS="$CXXFLAGS -Wno-unknown-warning-option"
fi
;;
irix*)
DEFINES="$DEFINES -DUNIX"

View File

@ -223,7 +223,7 @@ present in the debugger):</p>
<p>For space reasons, the Prompt, TIA, I/O and Audio displays are split into
4 tabs, only one of which is visible at a time. You can use the mouse or
keyboard to select which tab you want to view. Control/Cmd + Tab cycles between
tabs from left-to-right, Shift + Control/Cmd + Tab cycles right-to-left.
tabs from left-to-right, Shift-Control/Cmd + Tab cycles right-to-left.
Pressing Tab (or Shift + Tab) cycles between widgets in the current tab (except
for in the Prompt Tab, where 'tab' is used for something else).</p>
@ -339,7 +339,7 @@ previous rewind operation. The rewind buffer is 100 levels deep by default, the
size can be configured e.g. in the
<b><a href="index.html#Debugger">Developer Settings</a> - Time Machine</b> dialog.<p>
<p>The other operations are Step, Trace, Scan+1, Frame+1 and Run.</p>
<p>The other operations are Step, Trace, Scan +1, Frame +1 and Run.</p>
<p>You can also use the buttons from anywhere in the GUI via hotkeys.</p>
<p>
@ -349,48 +349,48 @@ size can be configured e.g. in the
<th>Function</th>
</tr>
<tr>
<td>Control-s</td>
<td>Control + S</td>
<td>Step</td>
</tr>
<tr>
<td>Control-t</td>
<td>Control + T</td>
<td>Trace</td>
</tr>
<tr>
<td>Control-L</td>
<td>Scan+1</td>
<td>Control + L</td>
<td>Scan +1</td>
</tr>
<tr>
<td>Control-f</td>
<td>Frame+1</td>
<td>Control + F</td>
<td>Frame +1</td>
</tr>
<tr>
<td>Alt-Left arrow</td>
<td>Alt + Left arrow</td>
<td>Rewind 1</td>
</tr>
<tr>
<td>Shift-Alt-Left arrow</td>
<td>Shift-Alt + Left arrow</td>
<td>Rewind 10</td>
</tr>
<tr>
<td>Alt-Down arrow</td>
<td>Alt + Down arrow</td>
<td>Rewind all</td>
</tr>
<tr>
<td>Alt-Right arrow</td>
<td>Alt + Right arrow</td>
<td>Unwind 1</td>
</tr>
<tr>
<td>Shift-Alt-Right arrow</td>
<td>Shift-Alt + Right arrow</td>
<td>Unwind 10</td>
</tr>
<tr>
<td>Alt-Up arrow</td>
<td>Alt + Up arrow</td>
<td>Unwind all</td>
</tr>
<tr>
<td>Backquote (`)</td>
<td>Run</td>
<td>Run, exits debugger</td>
</tr>
</table>
</p>
@ -433,18 +433,18 @@ Bash-style commands are also supported:</p>
<tr><td>End</td><td>Move cursor to end of line</td></tr>
<tr><td>Delete</td><td>Remove character to right of cursor</td></tr>
<tr><td>Backspace</td><td>Remove character to left of cursor</td></tr>
<tr><td>Control-a</td><td>Same function as 'Home'</td></tr>
<tr><td>Control-e</td><td>Same function as 'End'</td></tr>
<tr><td>Control-d</td><td>Same function as 'Delete'</td></tr>
<tr><td>Control-k</td><td>Remove all characters from cursor to end of line</td></tr>
<tr><td>Control-u</td><td>Remove all characters from cursor to beginning of line</td></tr>
<tr><td>Control-w</td><td>Remove entire word to left of cursor</td></tr>
<tr><td>Shift-PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
<tr><td>Shift-PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
<tr><td>Shift-Up</td><td>Scroll up through previous commands one line</td></tr>
<tr><td>Shift-Down</td><td>Scroll down through previous commands one line</td></tr>
<tr><td>Shift-Home</td><td>Scroll to beginning of commands</td></tr>
<tr><td>Shift-End</td><td>Scroll to end of commands</td></tr>
<tr><td>Control + A</td><td>Same function as 'Home'</td></tr>
<tr><td>Control + E</td><td>Same function as 'End'</td></tr>
<tr><td>Control + D</td><td>Same function as 'Delete'</td></tr>
<tr><td>Control + K</td><td>Remove all characters from cursor to end of line</td></tr>
<tr><td>Control + U</td><td>Remove all characters from cursor to beginning of line</td></tr>
<tr><td>Control + W</td><td>Remove entire word to left of cursor</td></tr>
<tr><td>Shift + PgUp</td><td>Scroll up through previous commands one screen/page</td></tr>
<tr><td>Shift + PgDown</td><td>Scroll down through previous commands one screen/page</td></tr>
<tr><td>Shift + Up</td><td>Scroll up through previous commands one line</td></tr>
<tr><td>Shift + Down</td><td>Scroll down through previous commands one line</td></tr>
<tr><td>Shift + Home</td><td>Scroll to beginning of commands</td></tr>
<tr><td>Shift + End</td><td>Scroll to end of commands</td></tr>
</table>
<p>You can also scroll with the mouse. Copy and paste is not yet supported.</p>
@ -989,12 +989,12 @@ clearsavestateifs - Clear all savestate points
runto - Run until string xx in disassembly
runtopc - Run until PC is set to value xx
s - Set Stack Pointer to value xx
save - Save breaks, watches, traps and functions to file xx
saveaccess - Save access counters to CSV file
save - Save breaks, watches, traps and functions to file xx (use ? for file dialog)
saveaccess - Save access counters to CSV file (use ? for file dialog)
saveconfig - Save DiStella config file (with default name)
savedis - Save DiStella disassembly (with default name)
saverom - Save (possibly patched) ROM (with default name)
saveses - Save console session (with default name)
savedis - Save DiStella disassembly (use ? for file dialog)
saverom - Save (possibly patched) ROM (use ? for file dialog)
saveses - Save console session (use ? for file dialog)
savesnap - Save current TIA image to PNG file
saveallstates - Save all emulator states
savestate - Save emulator state xx (valid args 0-9)

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheatManager::CheatManager(OSystem& osystem)
: myOSystem(osystem)
: myOSystem{osystem}
{
}
@ -253,8 +253,8 @@ void CheatManager::saveCheatDatabase()
return;
stringstream out;
for(const auto& iter: myCheatMap)
out << "\"" << iter.first << "\" " << "\"" << iter.second << "\"" << endl;
for(const auto& [md5, cheat]: myCheatMap)
out << "\"" << md5 << "\" " << "\"" << cheat << "\"" << endl;
try { myOSystem.cheatFile().write(out); }
catch(...) { return; }

View File

@ -23,9 +23,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code)
: Cheat(os, name, code),
address(0xf000 + unhex(code.substr(0, 3))),
value(uInt8(unhex(code.substr(3, 2)))),
count(uInt8(unhex(code.substr(5, 1)) + 1))
address{uInt16(0xf000 + unhex(code.substr(0, 3)))},
value{uInt8(unhex(code.substr(3, 2)))},
count{uInt8(unhex(code.substr(5, 1)) + 1)}
{
// Back up original data; we need this if the cheat is ever disabled
for(int i = 0; i < count; ++i)

View File

@ -25,8 +25,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RamCheat::RamCheat(OSystem& os, const string& name, const string& code)
: Cheat(os, name, code),
address(uInt16(unhex(myCode.substr(0, 2)))),
value(uInt8(unhex(myCode.substr(2, 2))))
address{uInt16(unhex(myCode.substr(0, 2)))},
value{uInt8(unhex(myCode.substr(2, 2)))}
{
}

View File

@ -22,10 +22,10 @@ using std::lock_guard;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AudioQueue::AudioQueue(uInt32 fragmentSize, uInt32 capacity, bool isStereo)
: myFragmentSize(fragmentSize),
myIsStereo(isStereo),
myFragmentQueue(capacity),
myAllFragments(capacity + 2)
: myFragmentSize{fragmentSize},
myIsStereo{isStereo},
myFragmentQueue{capacity},
myAllFragments{capacity + 2}
{
const uInt8 sampleSize = myIsStereo ? 2 : 1;
@ -48,7 +48,7 @@ uInt32 AudioQueue::capacity() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 AudioQueue::size()
uInt32 AudioQueue::size() const
{
lock_guard<mutex> guard(myMutex);

View File

@ -55,7 +55,7 @@ class AudioQueue
/**
Size getter.
*/
uInt32 size();
uInt32 size() const;
/**
Stereo / mono getter.
@ -120,7 +120,7 @@ class AudioQueue
uInt32 myNextFragment{0};
// We need a mutex for thread safety.
std::mutex myMutex;
mutable std::mutex myMutex;
// The first (empty) enqueue call returns this fragment.
Int16* myFirstFragmentForEnqueue{nullptr};

View File

@ -43,8 +43,7 @@ namespace {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AudioSettings::AudioSettings(Settings& settings)
: mySettings(settings),
myIsPersistent(true)
: mySettings{settings}
{
setPreset(normalizedPreset(mySettings.getInt(SETTING_PRESET)));
}

View File

@ -129,15 +129,15 @@ class AudioSettings
Settings& mySettings;
Preset myPreset;
Preset myPreset{Preset::custom};
uInt32 myPresetSampleRate;
uInt32 myPresetFragmentSize;
uInt32 myPresetBufferSize;
uInt32 myPresetHeadroom;
ResamplingQuality myPresetResamplingQuality;
uInt32 myPresetSampleRate{0};
uInt32 myPresetFragmentSize{0};
uInt32 myPresetBufferSize{0};
uInt32 myPresetHeadroom{0};
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeightbour};
bool myIsPersistent;
bool myIsPersistent{true};
};
#endif // AUDIO_PARAMTERS_HXX

View File

@ -23,7 +23,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
: EventHandler(osystem)
: EventHandler{osystem}
{
ASSERT_MAIN_THREAD;

View File

@ -31,7 +31,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
: myOSystem(osystem)
: myOSystem{osystem}
{
ASSERT_MAIN_THREAD;
@ -39,9 +39,8 @@ FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
if(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
{
ostringstream buf;
buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl;
Logger::error(buf.str());
throw runtime_error("FATAL ERROR");
buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError();
throw runtime_error(buf.str());
}
Logger::debug("FBBackendSDL2::FBBackendSDL2 SDL_Init()");

View File

@ -45,8 +45,8 @@ FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
uInt32 width, uInt32 height,
ScalingInterpolation inter,
const uInt32* staticData)
: myBackend(backend),
myInterpolationMode(inter)
: myBackend{backend},
myInterpolationMode{inter}
{
createSurface(width, height, staticData);
}

View File

@ -94,8 +94,8 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
FilesystemNodeZIP::FilesystemNodeZIP(
const string& zipfile, const string& virtualpath,
const AbstractFSNodePtr& realnode, bool isdir)
: _isDirectory(isdir),
_isFile(!isdir)
: _isDirectory{isdir},
_isFile{!isdir}
{
setFlags(zipfile, virtualpath, realnode);
}

View File

@ -116,7 +116,7 @@ class FilesystemNodeZIP : public AbstractFSNode
const char* start = str.c_str();
const char* cur = start + str.size() - 2;
while (cur >= start && !(*cur == '/' || *cur == '\\'))
while (cur >= start && *cur != FilesystemNode::PATH_SEPARATOR)
--cur;
return cur + 1;

View File

@ -19,12 +19,14 @@
using namespace std::chrono;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FpsMeter::FpsMeter(uInt32 queueSize)
: myQueue(queueSize)
: myQueue{queueSize}
{
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FpsMeter::reset(uInt32 garbageFrameLimit)
{
myQueue.clear();
@ -35,6 +37,7 @@ void FpsMeter::reset(uInt32 garbageFrameLimit)
myGarbageFrameLimit = garbageFrameLimit;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FpsMeter::render(uInt32 frameCount)
{
if (myGarbageFrameCounter < myGarbageFrameLimit) {
@ -67,6 +70,7 @@ void FpsMeter::render(uInt32 frameCount)
if (myTimeInterval > 0) myFps = (myFrameCount - first.frames) / myTimeInterval;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float FpsMeter::fps() const
{
return myFps;

View File

@ -0,0 +1,752 @@
//============================================================================
//
// 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-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
/*
Formats (all optional):
4, ; score digits
0, ; trailing zeroes
B, ; score format (BCD, HEX)
0, ; invert score order
B, ; variation format (BCD, HEX)
0, ; zero-based variation
"", ; special label (5 chars)
B, ; special format (BCD, HEX)
0, ; zero-based special
Addresses (in hex):
n-times xx, ; score info, high to low
xx, ; variation address (if more than 1 variation)
xx ; special address (if defined)
TODO:
- variation bits (Centipede)
- score swaps (Asteroids)
- special: one optional and named value extra per game (round, level...)
*/
#include <cmath>
#include "OSystem.hxx"
#include "PropsSet.hxx"
#include "System.hxx"
#include "Cart.hxx"
#include "Console.hxx"
#include "Launcher.hxx"
#include "Base.hxx"
#include "MD5.hxx"
#include "HighScoresManager.hxx"
using namespace BSPF;
using namespace std;
using namespace HSM;
using Common::Base;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HighScoresManager::HighScoresManager(OSystem& osystem)
: myOSystem{osystem}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int16 HighScoresManager::peek(uInt16 addr) const
{
if (myOSystem.hasConsole())
{
if(addr < 0x100u || myOSystem.console().cartridge().internalRamSize() == 0)
return myOSystem.console().system().peek(addr);
else
return myOSystem.console().cartridge().internalRamGetValue(addr);
}
return NO_VALUE;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const json HighScoresManager::properties(const Properties& props) const
{
const string& property = props.get(PropType::Cart_Highscore);
if(property.empty())
return json::array();
return json::parse(property);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json HighScoresManager::properties(json& jprops) const
{
Properties props;
if(myOSystem.hasConsole())
{
props = myOSystem.console().properties();
}
else
{
const string& md5 = myOSystem.launcher().selectedRomMD5();
myOSystem.propSet().getMD5(md5, props);
}
return jprops = properties(props);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::enabled() const
{
json hsProp;
return properties(hsProp).contains(SCORE_ADDRESSES);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numVariations(const json& jprops) const
{
return min(getPropInt(jprops, VARIATIONS_COUNT, DEFAULT_VARIATION), MAX_VARIATIONS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::get(const Properties& props, uInt32& numVariationsR,
ScoresProps& info) const
{
json jprops = properties(props);
numVariationsR = numVariations(jprops);
info.numDigits = numDigits(jprops);
info.trailingZeroes = trailingZeroes(jprops);
info.scoreBCD = scoreBCD(jprops);
info.scoreInvert = scoreInvert(jprops);
info.varsBCD = varBCD(jprops);
info.varsZeroBased = varZeroBased(jprops);
info.special = specialLabel(jprops);
info.specialBCD = specialBCD(jprops);
info.specialZeroBased = specialZeroBased(jprops);
info.notes = notes(jprops);
info.varsAddr = varAddress(jprops);
info.specialAddr = specialAddress(jprops);
info.scoreAddr = getPropScoreAddr(jprops);
return enabled();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::set(Properties& props, uInt32 numVariations,
const ScoresProps& info) const
{
json jprops = json::object();
// handle variations
jprops[VARIATIONS_COUNT] = min(numVariations, MAX_VARIATIONS);
if(numVariations != DEFAULT_VARIATION)
jprops[VARIATIONS_ADDRESS] = "0x" + Base::toString(info.varsAddr, Base::Fmt::_16);
if(info.varsBCD != DEFAULT_VARS_BCD)
jprops[VARIATIONS_BCD] = info.varsBCD;
if(info.varsZeroBased != DEFAULT_VARS_ZERO_BASED)
jprops[VARIATIONS_ZERO_BASED] = info.varsZeroBased;
// handle score
if(info.numDigits != DEFAULT_DIGITS)
jprops[SCORE_DIGITS] = info.numDigits;
if(info.trailingZeroes != DEFAULT_TRAILING)
jprops[SCORE_TRAILING_ZEROES] = info.trailingZeroes;
if(info.scoreBCD != DEFAULT_SCORE_BCD)
jprops[SCORE_BCD] = info.scoreBCD;
if(info.scoreInvert != DEFAULT_SCORE_REVERSED)
jprops[SCORE_INVERTED] = info.scoreInvert;
uInt32 addrBytes = numAddrBytes(info.numDigits, info.trailingZeroes);
json addresses = json::array();
for(uInt32 a = 0; a < addrBytes; ++a)
addresses.push_back("0x" + Base::toString(info.scoreAddr[a], Base::Fmt::_16));
jprops[SCORE_ADDRESSES] = addresses;
// handle special
if(!info.special.empty())
jprops[SPECIAL_LABEL] = info.special;
if(!info.special.empty())
jprops[SPECIAL_ADDRESS] = "0x" + Base::toString(info.specialAddr, Base::Fmt::_16);
if(info.specialBCD != DEFAULT_SPECIAL_BCD)
jprops[SPECIAL_BCD] = info.specialBCD;
if(info.specialZeroBased != DEFAULT_SPECIAL_ZERO_BASED)
jprops[SPECIAL_ZERO_BASED] = info.specialZeroBased;
// handle notes
if(!info.notes.empty())
jprops[NOTES] = info.notes;
props.set(PropType::Cart_Highscore, jprops.dump());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numDigits(const json& jprops) const
{
return min(getPropInt(jprops, SCORE_DIGITS, DEFAULT_DIGITS), MAX_SCORE_DIGITS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::trailingZeroes(const json& jprops) const
{
return min(getPropInt(jprops, SCORE_TRAILING_ZEROES, DEFAULT_TRAILING), MAX_TRAILING);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::scoreBCD(const json& jprops) const
{
return getPropBool(jprops, SCORE_BCD, DEFAULT_SCORE_BCD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::scoreInvert(const json& jprops) const
{
return getPropBool(jprops, SCORE_INVERTED, DEFAULT_SCORE_REVERSED);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::varBCD(const json& jprops) const
{
return getPropBool(jprops, VARIATIONS_BCD, DEFAULT_VARS_BCD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::varZeroBased(const json& jprops) const
{
return getPropBool(jprops, VARIATIONS_ZERO_BASED, DEFAULT_VARS_ZERO_BASED);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::specialLabel(const json& jprops) const
{
return getPropStr(jprops, SPECIAL_LABEL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::specialBCD(const json& jprops) const
{
return getPropBool(jprops, SPECIAL_BCD, DEFAULT_SPECIAL_BCD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::specialZeroBased(const json& jprops) const
{
return getPropBool(jprops, SPECIAL_ZERO_BASED, DEFAULT_SPECIAL_ZERO_BASED);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::notes(const json& jprops) const
{
return getPropStr(jprops, NOTES);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::varAddress(const json& jprops) const
{
return getPropAddr(jprops, VARIATIONS_ADDRESS, DEFAULT_ADDRESS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::specialAddress(const json& jprops) const
{
return getPropAddr(jprops, SPECIAL_ADDRESS, DEFAULT_ADDRESS);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numAddrBytes(Int32 digits, Int32 trailing) const
{
return (digits - trailing + 1) / 2;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::numAddrBytes(const json& jprops) const
{
return numAddrBytes(numDigits(jprops), trailingZeroes(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::numVariations() const
{
json jprops;
return numVariations(properties(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::specialLabel() const
{
json jprops;
return specialLabel(properties(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::variation(uInt16 addr, bool varBCD, bool zeroBased,
uInt32 numVariations) const
{
if (!myOSystem.hasConsole())
return DEFAULT_VARIATION;
Int32 var = peek(addr);
return convert(var, numVariations, varBCD, zeroBased);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::variation() const
{
json jprops;
uInt16 addr = varAddress(properties(jprops));
if(addr == DEFAULT_ADDRESS) {
if(numVariations() == 1)
return DEFAULT_VARIATION;
else
return NO_VALUE;
}
return variation(addr, varBCD(jprops), varZeroBased(jprops), numVariations(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::score(uInt32 numAddrBytes, uInt32 trailingZeroes,
bool isBCD, const ScoreAddresses& scoreAddr) const
{
if (!myOSystem.hasConsole())
return NO_VALUE;
Int32 totalScore = 0;
for (uInt32 b = 0; b < numAddrBytes; ++b)
{
uInt16 addr = scoreAddr[b];
Int32 score;
totalScore *= isBCD ? 100 : 256;
score = peek(addr);
if (isBCD)
{
score = fromBCD(score);
// verify if score is legit
if (score == NO_VALUE)
return NO_VALUE;
}
totalScore += score;
}
if (totalScore != NO_VALUE)
for (uInt32 i = 0; i < trailingZeroes; ++i)
totalScore *= 10;
return totalScore;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::score() const
{
json jprops;
uInt32 numBytes = numAddrBytes(properties(jprops));
const ScoreAddresses scoreAddr = getPropScoreAddr(jprops);
if(uInt32(scoreAddr.size()) < numBytes)
return NO_VALUE;
return score(numBytes, trailingZeroes(jprops), scoreBCD(jprops), scoreAddr);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::formattedScore(Int32 score, Int32 width) const
{
if(score <= 0)
return "";
ostringstream buf;
json jprops;
Int32 digits = numDigits(properties(jprops));
if(scoreBCD(jprops))
{
if(width > digits)
digits = width;
buf << std::setw(digits) << std::setfill(' ') << score;
}
else {
if(width > digits)
buf << std::setw(width - digits) << std::setfill(' ') << "";
buf << std::hex << std::setw(digits) << std::setfill('0') << score;
}
return buf.str();
}
string HighScoresManager::md5Props() const
{
json jprops;
properties(jprops);
ostringstream buf;
buf << varAddress(jprops) << numVariations() << varBCD(jprops)
<< varZeroBased(jprops);
uInt32 addrBytes = numAddrBytes(jprops);
HSM::ScoreAddresses addr = getPropScoreAddr(jprops);
for(uInt32 a = 0; a < addrBytes; ++a)
buf << addr[a];
buf << numDigits(jprops) << trailingZeroes(jprops) << scoreBCD(jprops)
<< scoreInvert(jprops) << specialAddress(jprops) << specialBCD(jprops)
<< specialZeroBased(jprops);
buf << specialAddress(jprops) << specialBCD(jprops) << specialZeroBased(jprops);
return MD5::hash(buf.str());
}
bool HighScoresManager::scoreInvert() const
{
json jprops;
return scoreInvert(properties(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::special() const
{
if(!myOSystem.hasConsole())
return NO_VALUE;
json jprops;
uInt16 addr = specialAddress(properties(jprops));
if (addr == DEFAULT_ADDRESS)
return NO_VALUE;
Int32 var = peek(addr);
if(specialBCD(jprops))
var = fromBCD(var);
var += specialZeroBased(jprops) ? 1 : 0;
return var;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::notes() const
{
json jprops;
return notes(properties(jprops));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const
{
//maxVal += zeroBased ? 0 : 1;
maxVal -= zeroBased ? 1 : 0;
Int32 bits = isBCD
? ceil(log(maxVal) / log(10) * 4)
: ceil(log(maxVal) / log(2));
// limit to maxVal's bits
val %= 1 << bits;
if (isBCD)
val = fromBCD(val);
if(val == NO_VALUE)
return 0;
val += zeroBased ? 1 : 0;
return val;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::getPropBool(const json& jprops, const string& key,
bool defVal) const
{
return jprops.contains(key) ? jprops.at(key).get<bool>() : defVal;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 HighScoresManager::getPropInt(const json& jprops, const string& key,
uInt32 defVal) const
{
return jprops.contains(key) ? jprops.at(key).get<uInt32>() : defVal;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::getPropStr(const json& jprops, const string& key,
const string& defVal) const
{
return jprops.contains(key) ? jprops.at(key).get<string>() : defVal;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::getPropAddr(const json& jprops, const string& key,
uInt16 defVal) const
{
const string str = getPropStr(jprops, key);
return str.empty() ? defVal : fromHexStr(str);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const HSM::ScoreAddresses HighScoresManager::getPropScoreAddr(const json& jprops) const
{
ScoreAddresses scoreAddr{};
if(jprops.contains(SCORE_ADDRESSES))
{
const json addrProps = jprops.at(SCORE_ADDRESSES);
if(!addrProps.empty() && addrProps.is_array())
{
int a = 0;
for(const json& addresses : addrProps)
{
const string address = addresses.get<string>();
if(address.empty())
scoreAddr[a++] = DEFAULT_ADDRESS;
else
scoreAddr[a++] = fromHexStr(address);
}
}
}
return scoreAddr;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 HighScoresManager::fromHexStr(const string& addr) const
{
string naked = addr;
if(int pos = naked.find("0x") != std::string::npos)
naked = naked.substr(pos + 1);
return stringToIntBase16(naked);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 HighScoresManager::fromBCD(uInt8 bcd) const
{
// verify if score is legit
if ((bcd & 0xF0) >= 0xA0 || (bcd & 0xF) >= 0xA)
return NO_VALUE;
return (bcd >> 4) * 10 + bcd % 16;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::saveHighScores(const string& cartName, ScoresData& data) const
{
ostringstream buf;
buf << myOSystem.stateDir() << cartName << ".hs" << data.variation;
// Make sure the file can be opened for writing
FilesystemNode node(buf.str());
if(!node.isWritable())
{
buf.str("");
buf << "Can't open/save to high scores file for variation " << data.variation;
myOSystem.frameBuffer().showTextMessage(buf.str());
}
// Do a complete high data save
if(!save(node, data))
{
buf.str("");
buf << "Error saving high scores for variation" << data.variation;
myOSystem.frameBuffer().showTextMessage(buf.str());
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HighScoresManager::loadHighScores(const string& cartName, ScoresData& data)
{
for(uInt32 r = 0; r < NUM_RANKS; ++r)
{
data.scores[r].score = 0;
data.scores[r].special = 0;
data.scores[r].name = "";
data.scores[r].date = "";
}
ostringstream buf;
buf << myOSystem.stateDir() << cartName << ".hs" << data.variation;
FilesystemNode node(buf.str());
stringstream in;
// Make sure the file can be opened
try {
node.read(in);
}
catch(...) { return; }
bool invalid = false;
try {
string highscores;
buf.str("");
if(getline(in, highscores) && highscores.length() != 0)
{
const json hsObject = json::parse(highscores);
if(hsObject.contains(DATA))
{
const json hsData = hsObject.at(DATA);
// First test if we have a valid header
// If so, do a complete high data load
if(!hsData.contains(VERSION) || hsData.at(VERSION) != HIGHSCORE_HEADER)
buf << "Error: Incompatible high scores file for variation "
<< data.variation << ".";
else
{
if(!load(hsData, data)
|| !hsData.contains(PROPCHECK) || hsData.at(PROPCHECK) != md5Props()
|| !hsObject.contains(CHECKSUM) || hsObject.at(CHECKSUM) != MD5::hash(hsData.dump()))
invalid = true;
else
return;
}
}
else
invalid = true;
}
}
catch(...) { invalid = true; }
if(invalid)
buf << "Error: Invalid data in high scores file for variation " << data.variation << ".";
myOSystem.frameBuffer().showTextMessage(buf.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::save(FilesystemNode& node, const ScoresData& data) const
{
try
{
json hsObject = json::object();
json hsData = json::object();
// Add header so that if the high score format changes in the future,
// we'll know right away, without having to parse the rest of the file
hsData[VERSION] = HIGHSCORE_HEADER;
hsData[MD5] = data.md5;
hsData[VARIATION] = data.variation;
json jScores = json::array();
for(uInt32 r = 0; r < NUM_RANKS && data.scores[r].score; ++r)
{
json jScore = json::object();
jScore[SCORE] = data.scores[r].score;
jScore[SPECIAL] = data.scores[r].special;
jScore[NAME] = data.scores[r].name;
jScore[DATE] = data.scores[r].date;
jScores.push_back(jScore);
}
hsData[SCORES] = jScores;
hsData[PROPCHECK] = md5Props();
hsObject[DATA] = hsData;
hsObject[CHECKSUM] = MD5::hash(hsData.dump());
stringstream ss(hsObject.dump());
node.write(ss);
}
catch(...)
{
cerr << "ERROR: HighScoresManager::save() exception\n";
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool HighScoresManager::load(const json& hsData, ScoresData& data)
{
if(!hsData.contains(MD5) || hsData.at(MD5) != data.md5
|| !hsData.contains(VARIATION) || hsData.at(VARIATION) != data.variation
|| !hsData.contains(SCORES))
return false;
const json& jScores = hsData.at(SCORES);
if(!jScores.empty() && jScores.is_array())
{
uInt32 r = 0;
for(const json& jScore : jScores)
{
if(jScore.contains(SCORE))
data.scores[r].score = jScore.at(SCORE).get<Int32>();
if(jScore.contains(SPECIAL))
data.scores[r].special = jScore.at(SPECIAL).get<Int32>();
if(jScore.contains(NAME))
data.scores[r].name = jScore.at(NAME).get<string>();
if(jScore.contains(DATE))
data.scores[r].date = jScore.at(DATE).get<string>();
if(++r == NUM_RANKS)
break;
}
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string HighScoresManager::VARIATIONS_COUNT = "variations_count";
const string HighScoresManager::VARIATIONS_ADDRESS = "variations_address";
const string HighScoresManager::VARIATIONS_BCD = "variations_bcd";
const string HighScoresManager::VARIATIONS_ZERO_BASED = "variations_zero_based";
const string HighScoresManager::SCORE_DIGITS = "score_digits";
const string HighScoresManager::SCORE_TRAILING_ZEROES = "score_trailing_zeroes";
const string HighScoresManager::SCORE_BCD = "score_bcd";
const string HighScoresManager::SCORE_INVERTED = "score_inverted";
const string HighScoresManager::SCORE_ADDRESSES = "score_addresses";
const string HighScoresManager::SPECIAL_LABEL = "special_label";
const string HighScoresManager::SPECIAL_ADDRESS = "special_address";
const string HighScoresManager::SPECIAL_BCD = "special_bcd";
const string HighScoresManager::SPECIAL_ZERO_BASED = "special_zero_based";
const string HighScoresManager::NOTES = "notes";
const string HighScoresManager::DATA = "data";
const string HighScoresManager::VERSION = "version";
const string HighScoresManager::MD5 = "md5";
const string HighScoresManager::VARIATION = "variation";
const string HighScoresManager::SCORES = "scores";
const string HighScoresManager::SCORE = "score";
const string HighScoresManager::SPECIAL = "special";
const string HighScoresManager::NAME = "name";
const string HighScoresManager::DATE = "date";
const string HighScoresManager::PROPCHECK = "propcheck";
const string HighScoresManager::CHECKSUM = "checksum";

View File

@ -0,0 +1,265 @@
//============================================================================
//
// 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-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef HIGHSCORES_MANAGER_HXX
#define HIGHSCORES_MANAGER_HXX
#define HIGHSCORE_HEADER "06010000highscores"
class OSystem;
#include "Props.hxx"
#include "json_lib.hxx"
#include "FSNode.hxx"
using json = nlohmann::json;
/**
This class provides an interface to all things related to high scores.
@author Thomas Jentzsch
*/
namespace HSM {
static constexpr uInt32 MAX_SCORE_DIGITS = 8;
static constexpr uInt32 MAX_ADDR_CHARS = MAX_SCORE_DIGITS / 2;
static constexpr uInt32 MAX_SCORE_ADDR = 4;
static constexpr uInt32 MAX_SPECIAL_NAME = 5;
static constexpr uInt32 MAX_SPECIAL_DIGITS = 3;
static constexpr uInt32 DEFAULT_VARIATION = 1;
static constexpr uInt32 DEFAULT_ADDRESS = 0;
static constexpr Int32 NO_VALUE = -1;
using ScoreAddresses = array<Int16, MAX_SCORE_ADDR>;
static const uInt32 NUM_RANKS = 10;
struct ScoresProps {
// Formats
uInt32 numDigits;
uInt32 trailingZeroes;
bool scoreBCD;
bool scoreInvert;
bool varsBCD;
bool varsZeroBased;
string special;
bool specialBCD;
bool specialZeroBased;
string notes;
// Addresses
ScoreAddresses scoreAddr;
uInt16 varsAddr;
uInt16 specialAddr;
};
struct ScoreEntry {
Int32 score;
Int32 special;
string name;
string date;
};
struct ScoresData {
Int32 variation;
string md5;
ScoreEntry scores[NUM_RANKS];
};
} // namespace HSM
/**
This class provides an interface to define, load and save scores. It is meant
for games which do not support saving highscores.
@author Thomas Jentzsch
*/
class HighScoresManager
{
public:
explicit HighScoresManager(OSystem& osystem);
virtual ~HighScoresManager() = default;
// check if high score data has been defined
bool enabled() const;
/**
Get the highscore data of game's properties
@return True if highscore data exists, else false
*/
bool get(const Properties& props, uInt32& numVariations,
HSM::ScoresProps& info) const;
/**
Set the highscore data of game's properties
*/
void set(Properties& props, uInt32 numVariations,
const HSM::ScoresProps& info) const;
/**
Calculate the score from given parameters
@return The current score or -1 if no valid data exists
*/
Int32 score(uInt32 numAddrBytes, uInt32 trailingZeroes, bool isBCD,
const HSM::ScoreAddresses& scoreAddr) const;
// Convert the given value, using only the maximum bits required by maxVal
// and adjusted for BCD and zero based data
Int32 convert(Int32 val, uInt32 maxVal, bool isBCD, bool zeroBased) const;
/**
Calculate the number of bytes for one player's score from given parameters
@return The number of score address bytes
*/
uInt32 numAddrBytes(Int32 digits, Int32 trailing) const;
// Retrieve current values (using game's properties)
Int32 numVariations() const;
const string specialLabel() const;
Int32 variation() const;
Int32 score() const;
const string formattedScore(Int32 score, Int32 width = -1) const;
bool scoreInvert() const;
Int32 special() const;
const string notes() const;
// Get md5 property definition checksum
string md5Props() const;
// Peek into memory
Int16 peek(uInt16 addr) const;
void saveHighScores(const string& cartName, HSM::ScoresData& scores) const;
void loadHighScores(const string& cartName, HSM::ScoresData& scores);
private:
static const string VARIATIONS_COUNT;
static const string VARIATIONS_ADDRESS;
static const string VARIATIONS_BCD;
static const string VARIATIONS_ZERO_BASED;
static const string SCORE_DIGITS;
static const string SCORE_TRAILING_ZEROES;
static const string SCORE_BCD;
static const string SCORE_INVERTED;
static const string SCORE_ADDRESSES;
static const string SPECIAL_LABEL;
static const string SPECIAL_ADDRESS;
static const string SPECIAL_BCD;
static const string SPECIAL_ZERO_BASED;
static const string NOTES;
static constexpr uInt32 MAX_VARIATIONS = 256;
static constexpr uInt32 MAX_TRAILING = 3;
static constexpr uInt32 DEFAULT_DIGITS = 4;
static constexpr uInt32 DEFAULT_TRAILING = 0;
static constexpr bool DEFAULT_SCORE_BCD = true;
static constexpr bool DEFAULT_SCORE_REVERSED = false;
static constexpr bool DEFAULT_VARS_BCD = true;
static constexpr bool DEFAULT_VARS_ZERO_BASED = false;
static constexpr bool DEFAULT_SPECIAL_BCD = true;
static constexpr bool DEFAULT_SPECIAL_ZERO_BASED = false;
static const string DATA;
static const string VERSION;
static const string MD5;
static const string VARIATION;
static const string SCORES;
static const string SCORE;
static const string SPECIAL;
static const string NAME;
static const string DATE;
static const string PROPCHECK;
static const string CHECKSUM;
private:
// Retrieve current values from (using given parameters)
Int32 variation(uInt16 addr, bool varBCD, bool zeroBased, uInt32 numVariations) const;
// Get individual highscore info from properties
uInt32 numVariations(const json& jprops) const;
uInt16 varAddress(const json& jprops) const;
uInt16 specialAddress(const json& jprops) const;
uInt32 numDigits(const json& jprops) const;
uInt32 trailingZeroes(const json& jprops) const;
bool scoreBCD(const json& jprops) const;
bool scoreInvert(const json& jprops) const;
bool varBCD(const json& jprops) const;
bool varZeroBased(const json& jprops) const;
const string specialLabel(const json& jprops) const;
bool specialBCD(const json& jprops) const;
bool specialZeroBased(const json& jprops) const;
const string notes(const json& jprops) const;
// Calculate the number of bytes for one player's score from property parameters
uInt32 numAddrBytes(const json& jprops) const;
// Get properties
const json properties(const Properties& props) const;
json properties(json& jprops) const;
// Get value from highscore properties for given key
bool getPropBool(const json& jprops, const string& key,
bool defVal = false) const;
uInt32 getPropInt(const json& jprops, const string& key,
uInt32 defVal = 0) const;
const string getPropStr(const json& jprops, const string& key,
const string& defVal = "") const;
uInt16 getPropAddr(const json& jprops, const string& key,
uInt16 defVal = 0) const;
const HSM::ScoreAddresses getPropScoreAddr(const json& jprops) const;
uInt16 fromHexStr(const string& addr) const;
Int32 fromBCD(uInt8 bcd) const;
/**
Saves the current high scores for this game and variation to the given file system node.
@param node The file system node to save to.
@param scores The saved high score data
@return The result of the save. True on success, false on failure.
*/
bool save(FilesystemNode& node, const HSM::ScoresData& scores) const;
/**
Loads the current high scores for this game and variation from the given JSON object.
@param hsData The JSON to parse
@param scores The loaded high score data
@return The result of the load. True on success, false on failure.
*/
bool load(const json& hsData, HSM::ScoresData& scores);
private:
// Reference to the osystem object
OSystem& myOSystem;
private:
// Following constructors and assignment operators not supported
HighScoresManager() = delete;
HighScoresManager(const HighScoresManager&) = delete;
HighScoresManager(HighScoresManager&&) = delete;
HighScoresManager& operator=(const HighScoresManager&) = delete;
HighScoresManager& operator=(HighScoresManager&&) = delete;
};
#endif

View File

@ -66,7 +66,7 @@ void JoyMap::erase(const EventMode mode, const int button,
Event::Type JoyMap::get(const JoyMapping& mapping) const
{
auto find = myMap.find(mapping);
if (find != myMap.end())
if(find != myMap.end())
return find->second;
// try without button as modifier
@ -75,7 +75,7 @@ Event::Type JoyMap::get(const JoyMapping& mapping) const
m.button = JOY_CTRL_NONE;
find = myMap.find(m);
if (find != myMap.end())
if(find != myMap.end())
return find->second;
return Event::Type::NoType;
@ -96,7 +96,7 @@ Event::Type JoyMap::get(const EventMode mode, const int button,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool JoyMap::check(const JoyMapping & mapping) const
bool JoyMap::check(const JoyMapping& mapping) const
{
auto find = myMap.find(mapping);
@ -117,14 +117,14 @@ string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
ostringstream buf;
// button description
if (mapping.button != JOY_CTRL_NONE)
if(mapping.button != JOY_CTRL_NONE)
buf << "/B" << mapping.button;
// axis description
if (mapping.axis != JoyAxis::NONE)
if(mapping.axis != JoyAxis::NONE)
{
buf << "/A";
switch (mapping.axis)
switch(mapping.axis)
{
case JoyAxis::X: buf << "X"; break;
case JoyAxis::Y: buf << "Y"; break;
@ -132,19 +132,19 @@ string JoyMap::getDesc(const Event::Type event, const JoyMapping& mapping) const
default: buf << int(mapping.axis); break;
}
if (Event::isAnalog(event))
if(Event::isAnalog(event))
buf << "+|-";
else if (mapping.adir == JoyDir::NEG)
else if(mapping.adir == JoyDir::NEG)
buf << "-";
else
buf << "+";
}
// hat description
if (mapping.hat != JOY_CTRL_NONE)
if(mapping.hat != JOY_CTRL_NONE)
{
buf << "/H" << mapping.hat;
switch (mapping.hdir)
switch(mapping.hdir)
{
case JoyHatDir::UP: buf << "Y+"; break;
case JoyHatDir::DOWN: buf << "Y-"; break;
@ -162,13 +162,13 @@ string JoyMap::getEventMappingDesc(int stick, const Event::Type event, const Eve
{
ostringstream buf;
for (auto item : myMap)
for (const auto& [_mapping, _event]: myMap)
{
if (item.second == event && item.first.mode == mode)
if (_event == event && _mapping.mode == mode)
{
if (buf.str() != "")
if(buf.str() != "")
buf << ", ";
buf << "J" << stick << getDesc(event, item.first);
buf << "J" << stick << getDesc(event, _mapping);
}
}
return buf.str();
@ -179,9 +179,9 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E
{
JoyMappingArray map;
for (auto item : myMap)
if (item.second == event && item.first.mode == mode)
map.push_back(item.first);
for (const auto& [_mapping, _event]: myMap)
if (_event == event && _mapping.mode == mode)
map.push_back(_mapping);
return map;
}
@ -189,25 +189,51 @@ JoyMap::JoyMappingArray JoyMap::getEventMapping(const Event::Type event, const E
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json JoyMap::saveMapping(const EventMode mode) const
{
using MapType = std::pair<JoyMapping, Event::Type>;
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
std::sort(sortedMap.begin(), sortedMap.end(),
[](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.button != b.first.button)
return a.first.button < b.first.button;
if(a.first.axis != b.first.axis)
return a.first.axis < b.first.axis;
if(a.first.adir != b.first.adir)
return a.first.adir < b.first.adir;
if(a.first.hat != b.first.hat)
return a.first.hat < b.first.hat;
if(a.first.hdir != b.first.hdir)
return a.first.hdir < b.first.hdir;
return a.second < b.second;
}
);
json eventMappings = json::array();
for (auto& item: myMap) {
if (item.first.mode != mode) continue;
for (const auto& [_mapping, _event]: sortedMap) {
if (_mapping.mode != mode) continue;
json eventMapping = json::object();
eventMapping["event"] = item.second;
eventMapping["event"] = _event;
if (item.first.button != JOY_CTRL_NONE) eventMapping["button"] = item.first.button;
if (_mapping.button != JOY_CTRL_NONE) eventMapping["button"] = _mapping.button;
if (item.first.axis != JoyAxis::NONE) {
eventMapping["axis"] = item.first.axis;
eventMapping["axisDirection"] = item.first.adir;
if (_mapping.axis != JoyAxis::NONE) {
eventMapping["axis"] = _mapping.axis;
eventMapping["axisDirection"] = _mapping.adir;
}
if (item.first.hat != -1) {
eventMapping["hat"] = item.first.hat;
eventMapping["hatDirection"] = item.first.hdir;
if (_mapping.hat != -1) {
eventMapping["hat"] = _mapping.hat;
eventMapping["hatDirection"] = _mapping.hdir;
}
eventMappings.push_back(eventMapping);
@ -221,7 +247,7 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
{
int i = 0;
for (const json& eventMapping: eventMappings) {
for(const json& eventMapping : eventMappings) {
int button = eventMapping.contains("button") ? eventMapping.at("button").get<int>() : JOY_CTRL_NONE;
JoyAxis axis = eventMapping.contains("axis") ? eventMapping.at("axis").get<JoyAxis>() : JoyAxis::NONE;
JoyDir axisDirection = eventMapping.contains("axis") ? eventMapping.at("axisDirection").get<JoyDir>() : JoyDir::NONE;
@ -240,7 +266,7 @@ int JoyMap::loadMapping(const json& eventMappings, const EventMode mode)
);
i++;
} catch (json::exception) {
} catch (const json::exception&) {
Logger::error("ignoring invalid joystick event");
}
}
@ -262,22 +288,22 @@ json JoyMap::convertLegacyMapping(string list)
istringstream buf(list);
int event, button, axis, adir, hat, hdir;
while (buf >> event && buf >> button
&& buf >> axis && buf >> adir
&& buf >> hat && buf >> hdir)
while(buf >> event && buf >> button
&& buf >> axis && buf >> adir
&& buf >> hat && buf >> hdir)
{
json eventMapping = json::object();
eventMapping["event"] = Event::Type(event);
if (button != JOY_CTRL_NONE) eventMapping["button"] = button;
if(button != JOY_CTRL_NONE) eventMapping["button"] = button;
if (JoyAxis(axis) != JoyAxis::NONE) {
if(JoyAxis(axis) != JoyAxis::NONE) {
eventMapping["axis"] = JoyAxis(axis);
eventMapping["axisDirection"] = JoyDir(adir);
}
if (hat != -1) {
if(hat != -1) {
eventMapping["hat"] = hat;
eventMapping["hatDirection"] = JoyHatDir(hdir);
}
@ -291,8 +317,8 @@ json JoyMap::convertLegacyMapping(string list)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::eraseMode(const EventMode mode)
{
for (auto item = myMap.begin(); item != myMap.end();)
if (item->first.mode == mode) {
for(auto item = myMap.begin(); item != myMap.end();)
if(item->first.mode == mode) {
auto _item = item++;
erase(_item->first);
}
@ -302,8 +328,8 @@ void JoyMap::eraseMode(const EventMode mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void JoyMap::eraseEvent(const Event::Type event, const EventMode mode)
{
for (auto item = myMap.begin(); item != myMap.end();)
if (item->second == event && item->first.mode == mode) {
for(auto item = myMap.begin(); item != myMap.end();)
if(item->second == event && item->first.mode == mode) {
auto _item = item++;
erase(_item->first);
}

View File

@ -22,7 +22,7 @@
#include "Event.hxx"
#include "EventHandlerConstants.hxx"
#include "json.hxx"
#include "json_lib.hxx"
/**
This class handles controller mappings in Stella.
@ -44,19 +44,19 @@ class JoyMap
explicit JoyMapping(EventMode c_mode, int c_button,
JoyAxis c_axis, JoyDir c_adir,
int c_hat, JoyHatDir c_hdir)
: mode(c_mode), button(c_button),
axis(c_axis), adir(c_adir),
hat(c_hat), hdir(c_hdir) { }
: mode{c_mode}, button{c_button},
axis{c_axis}, adir{c_adir},
hat{c_hat}, hdir{c_hdir} { }
explicit JoyMapping(EventMode c_mode, int c_button,
JoyAxis c_axis, JoyDir c_adir)
: mode(c_mode), button(c_button),
axis(c_axis), adir(c_adir),
hat(JOY_CTRL_NONE), hdir(JoyHatDir::CENTER) { }
: mode{c_mode}, button{c_button},
axis{c_axis}, adir{c_adir},
hat{JOY_CTRL_NONE}, hdir{JoyHatDir::CENTER} { }
explicit JoyMapping(EventMode c_mode, int c_button,
int c_hat, JoyHatDir c_hdir)
: mode(c_mode), button(c_button),
axis(JoyAxis::NONE), adir(JoyDir::NONE),
hat(c_hat), hdir(c_hdir) { }
: mode{c_mode}, button{c_button},
axis{JoyAxis::NONE}, adir{JoyDir::NONE},
hat{c_hat}, hdir{c_hdir} { }
JoyMapping(const JoyMapping&) = default;
JoyMapping& operator=(const JoyMapping&) = default;

View File

@ -22,6 +22,52 @@
using json = nlohmann::json;
namespace {
json serializeModkeyMask(int mask)
{
if(mask == StellaMod::KBDM_NONE) return json(nullptr);
json serializedMask = json::array();
for(StellaMod mod: {
StellaMod::KBDM_CTRL,
StellaMod::KBDM_SHIFT,
StellaMod::KBDM_ALT,
StellaMod::KBDM_GUI,
StellaMod::KBDM_LSHIFT,
StellaMod::KBDM_RSHIFT,
StellaMod::KBDM_LCTRL,
StellaMod::KBDM_RCTRL,
StellaMod::KBDM_LALT,
StellaMod::KBDM_RALT,
StellaMod::KBDM_LGUI,
StellaMod::KBDM_RGUI,
StellaMod::KBDM_NUM,
StellaMod::KBDM_CAPS,
StellaMod::KBDM_MODE,
StellaMod::KBDM_RESERVED
}) {
if((mask & mod) != mod) continue;
serializedMask.push_back(json(mod));
mask &= ~mod;
}
return serializedMask.size() == 1 ? serializedMask.at(0) : serializedMask;
}
int deserializeModkeyMask(json serializedMask)
{
if(serializedMask.is_null()) return StellaMod::KBDM_NONE;
if(!serializedMask.is_array()) return serializedMask.get<StellaMod>();
int mask = 0;
for(const json& mod: serializedMask) mask |= mod.get<StellaMod>();
return mask;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::add(const Event::Type event, const Mapping& mapping)
{
@ -51,10 +97,10 @@ Event::Type KeyMap::get(const Mapping& mapping) const
{
Mapping m = convertMod(mapping);
if (myModEnabled)
if(myModEnabled)
{
auto find = myMap.find(m);
if (find != myMap.end())
if(find != myMap.end())
return find->second;
}
@ -62,7 +108,7 @@ Event::Type KeyMap::get(const Mapping& mapping) const
m.mod = StellaMod(0);
auto find = myMap.find(m);
if (find != myMap.end())
if(find != myMap.end())
return find->second;
return Event::Type::NoType;
@ -112,26 +158,26 @@ string KeyMap::getDesc(const Mapping& mapping) const
int RMOD3 = KBDM_RALT;
#endif
if ((mapping.mod & KBDM_CTRL) == KBDM_CTRL) buf << "Ctrl";
else if (mapping.mod & KBDM_LCTRL) buf << "Left Ctrl";
else if (mapping.mod & KBDM_RCTRL) buf << "Right Ctrl";
if((mapping.mod & KBDM_CTRL) == KBDM_CTRL) buf << "Ctrl";
else if(mapping.mod & KBDM_LCTRL) buf << "Left Ctrl";
else if(mapping.mod & KBDM_RCTRL) buf << "Right Ctrl";
if ((mapping.mod & (MOD2)) && buf.tellp()) buf << "+";
if ((mapping.mod & MOD2) == MOD2) buf << mod2;
else if (mapping.mod & LMOD2) buf << "Left " << mod2;
else if (mapping.mod & RMOD2) buf << "Right " << mod2;
if((mapping.mod & (MOD2)) && buf.tellp()) buf << "+";
if((mapping.mod & MOD2) == MOD2) buf << mod2;
else if(mapping.mod & LMOD2) buf << "Left " << mod2;
else if(mapping.mod & RMOD2) buf << "Right " << mod2;
if ((mapping.mod & (MOD3)) && buf.tellp()) buf << "+";
if ((mapping.mod & MOD3) == MOD3) buf << mod3;
else if (mapping.mod & LMOD3) buf << "Left " << mod3;
else if (mapping.mod & RMOD3) buf << "Right " << mod3;
if((mapping.mod & (MOD3)) && buf.tellp()) buf << "+";
if((mapping.mod & MOD3) == MOD3) buf << mod3;
else if(mapping.mod & LMOD3) buf << "Left " << mod3;
else if(mapping.mod & RMOD3) buf << "Right " << mod3;
if ((mapping.mod & (KBDM_SHIFT)) && buf.tellp()) buf << "+";
if ((mapping.mod & KBDM_SHIFT) == KBDM_SHIFT) buf << "Shift";
else if (mapping.mod & KBDM_LSHIFT) buf << "Left Shift";
else if (mapping.mod & KBDM_RSHIFT) buf << "Right Shift";
if((mapping.mod & (KBDM_SHIFT)) && buf.tellp()) buf << "+";
if((mapping.mod & KBDM_SHIFT) == KBDM_SHIFT) buf << "Shift";
else if(mapping.mod & KBDM_LSHIFT) buf << "Left Shift";
else if(mapping.mod & KBDM_RSHIFT) buf << "Right Shift";
if (buf.tellp()) buf << "+";
if(buf.tellp()) buf << "+";
buf << StellaKeyName::forKey(mapping.key);
return buf.str();
@ -148,13 +194,13 @@ string KeyMap::getEventMappingDesc(const Event::Type event, const EventMode mode
{
ostringstream buf;
for (auto item : myMap)
for (const auto& [_mapping, _event]: myMap)
{
if (item.second == event && item.first.mode == mode)
if (_event == event && _mapping.mode == mode)
{
if (buf.str() != "")
if(buf.str() != "")
buf << ", ";
buf << getDesc(item.first);
buf << getDesc(_mapping);
}
}
return buf.str();
@ -165,9 +211,9 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even
{
MappingArray map;
for (auto item : myMap)
if (item.second == event && item.first.mode == mode)
map.push_back(item.first);
for (const auto& [_mapping, _event]: myMap)
if (_event == event && _mapping.mode == mode)
map.push_back(_mapping);
return map;
}
@ -175,18 +221,35 @@ KeyMap::MappingArray KeyMap::getEventMapping(const Event::Type event, const Even
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json KeyMap::saveMapping(const EventMode mode) const
{
using MapType = std::pair<Mapping, Event::Type>;
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
std::sort(sortedMap.begin(), sortedMap.end(),
[](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.key != b.first.key)
return a.first.key < b.first.key;
if(a.first.mod != b.first.mod)
return a.first.mod < b.first.mod;
return a.second < b.second;
}
);
json mappings = json::array();
for (auto item : myMap) {
if (item.first.mode != mode) continue;
for (const auto& [_mapping, _event]: sortedMap) {
if (_mapping.mode != mode) continue;
json mapping = json::object();
mapping["event"] = item.second;
mapping["key"] = item.first.key;
mapping["event"] = _event;
mapping["key"] = _mapping.key;
if (item.first.mod != StellaMod::KBDM_NONE)
mapping["mod"] = item.first.mod;
if (_mapping.mod != StellaMod::KBDM_NONE)
mapping["mod"] = serializeModkeyMask(_mapping.mod);
mappings.push_back(mapping);
}
@ -198,17 +261,18 @@ json KeyMap::saveMapping(const EventMode mode) const
int KeyMap::loadMapping(const json& mappings, const EventMode mode) {
int i = 0;
for (const json& mapping: mappings) {
for(const json& mapping : mappings)
{
try {
add(
mapping.at("event").get<Event::Type>(),
mode,
mapping.at("key").get<StellaKey>(),
mapping.contains("mod") ? mapping.at("mod").get<StellaMod>() : StellaMod::KBDM_NONE
mapping.contains("mod") ? deserializeModkeyMask(mapping.at("mod")) : StellaMod::KBDM_NONE
);
i++;
} catch (json::exception) {
} catch (const json::exception&) {
Logger::error("ignoring bad keyboard mapping");
}
}
@ -229,13 +293,15 @@ json KeyMap::convertLegacyMapping(string list)
istringstream buf(list);
int event, key, mod;
while (buf >> event && buf >> key && buf >> mod) {
while(buf >> event && buf >> key && buf >> mod)
{
json mapping = json::object();
mapping["event"] = Event::Type(event);
mapping["key"] = StellaKey(key);
if (StellaMod(mod) != StellaMod::KBDM_NONE) mapping["mod"] = StellaMod(mod);
if(StellaMod(mod) != StellaMod::KBDM_NONE)
mapping["mod"] = serializeModkeyMask(StellaMod(mod));
convertedMapping.push_back(mapping);
}
@ -246,8 +312,8 @@ json KeyMap::convertLegacyMapping(string list)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::eraseMode(const EventMode mode)
{
for (auto item = myMap.begin(); item != myMap.end();)
if (item->first.mode == mode) {
for(auto item = myMap.begin(); item != myMap.end();)
if(item->first.mode == mode) {
auto _item = item++;
erase(_item->first);
}
@ -257,8 +323,8 @@ void KeyMap::eraseMode(const EventMode mode)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void KeyMap::eraseEvent(const Event::Type event, const EventMode mode)
{
for (auto item = myMap.begin(); item != myMap.end();)
if (item->second == event && item->first.mode == mode) {
for(auto item = myMap.begin(); item != myMap.end();)
if(item->second == event && item->first.mode == mode) {
auto _item = item++;
erase(_item->first);
}
@ -270,7 +336,7 @@ KeyMap::Mapping KeyMap::convertMod(const Mapping& mapping) const
{
Mapping m = mapping;
if (m.key >= KBDK_LCTRL && m.key <= KBDK_RGUI)
if(m.key >= KBDK_LCTRL && m.key <= KBDK_RGUI)
// handle solo modifier keys differently
m.mod = KBDM_NONE;
else

View File

@ -22,7 +22,7 @@
#include "Event.hxx"
#include "EventHandlerConstants.hxx"
#include "StellaKeys.hxx"
#include "json.hxx"
#include "json_lib.hxx"
/**
This class handles keyboard mappings in Stella.
@ -39,9 +39,9 @@ class KeyMap
StellaMod mod{StellaMod(0)};
explicit Mapping(EventMode c_mode, StellaKey c_key, StellaMod c_mod)
: mode(c_mode), key(c_key), mod(c_mod) { }
: mode{c_mode}, key{c_key}, mod{c_mod} { }
explicit Mapping(EventMode c_mode, int c_key, int c_mod)
: mode(c_mode), key(StellaKey(c_key)), mod(StellaMod(c_mod)) { }
: mode{c_mode}, key{StellaKey(c_key)}, mod{StellaMod(c_mod)} { }
Mapping(const Mapping&) = default;
Mapping& operator=(const Mapping&) = default;
Mapping(Mapping&&) = default;

View File

@ -24,9 +24,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MouseControl::MouseControl(Console& console, const string& mode)
: myProps(console.properties()),
myLeftController(console.leftController()),
myRightController(console.rightController())
: myProps{console.properties()},
myLeftController{console.leftController()},
myRightController{console.rightController()}
{
istringstream m_axis(mode);
string m_mode;
@ -137,13 +137,17 @@ MouseControl::MouseControl(Console& console, const string& mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string& MouseControl::next()
const string& MouseControl::change(int direction)
{
myCurrentModeNum = BSPF::clampw(myCurrentModeNum + direction, 0, int(myModeList.size() - 1));
const MouseMode& mode = myModeList[myCurrentModeNum];
myCurrentModeNum = (myCurrentModeNum + 1) % myModeList.size();
myLeftController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid);
myRightController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid);
bool leftControl =
myLeftController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid);
bool rightControl =
myRightController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid);
myHasMouseControl = leftControl || rightControl;
return mode.message;
}

View File

@ -62,7 +62,12 @@ class MouseControl
@return A message explaining the current mouse mode
*/
const string& next();
const string& change(int direction = +1);
/**
Get whether any current controller supports mouse control
*/
bool hasMouseControl() const { return myHasMouseControl; }
private:
void addLeftControllerModes(bool noswap);
@ -101,6 +106,7 @@ class MouseControl
int myCurrentModeNum{0};
vector<MouseMode> myModeList;
bool myHasMouseControl{false};
private:
// Following constructors and assignment operators not supported

View File

@ -19,6 +19,9 @@
#include "OSystem.hxx"
#include "Console.hxx"
#include "Joystick.hxx"
#include "Paddles.hxx"
#include "PointingDevice.hxx"
#include "Driving.hxx"
#include "Settings.hxx"
#include "EventHandler.hxx"
#include "PJoystickHandler.hxx"
@ -33,8 +36,8 @@ using json = nlohmann::json;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::PhysicalJoystickHandler(
OSystem& system, EventHandler& handler)
: myOSystem(system),
myHandler(handler)
: myOSystem{system},
myHandler{handler}
{
if(myOSystem.settings().getInt("event_ver") != Event::VERSION) {
Logger::info("event version mismatch; dropping previous joystick mappings");
@ -47,7 +50,7 @@ PhysicalJoystickHandler::PhysicalJoystickHandler(
try {
mappings = json::parse(serializedMapping);
} catch (json::exception) {
} catch (const json::exception&) {
Logger::info("converting legacy joystick mappings");
mappings = convertLegacyMapping(serializedMapping);
@ -122,8 +125,8 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
// For non-unique names that already have a database entry,
// we append ' #x', where 'x' increases consecutively
int count = 0;
for(const auto& i: myDatabase)
if(BSPF::startsWithIgnoreCase(i.first, stick->name) && i.second.joy)
for(const auto& [_name, _info]: myDatabase)
if(BSPF::startsWithIgnoreCase(_name, stick->name) && _info.joy)
++count;
if(count > 0)
@ -132,12 +135,13 @@ int PhysicalJoystickHandler::add(const PhysicalJoystickPtr& stick)
name << stick->name << " #" << count+1;
stick->name = name.str();
}
stick->type = PhysicalJoystick::JT_REGULAR;
stick->type = PhysicalJoystick::Type::REGULAR;
}
// The stick *must* be inserted here, since it may be used below
mySticks[stick->ID] = stick;
// Map the stelladaptors we've found according to the specified ports
// The 'type' is also set there
if(specialAdaptor)
mapStelladaptors(myOSystem.settings().getString("saport"));
@ -217,45 +221,45 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
// We know there will be only two such devices (at most), since the logic
// in setupJoysticks take care of that
int saCount = 0;
int saOrder[NUM_PORTS] = { 1, 2 };
int saOrder[] = { 1, 2 };
if(BSPF::equalsIgnoreCase(saport, "rl"))
{
saOrder[0] = 2; saOrder[1] = 1;
}
for(auto& stick: mySticks)
for(auto& [_id, _joyptr]: mySticks)
{
// remove previously added emulated ports
size_t pos = stick.second->name.find(" (emulates ");
size_t pos = _joyptr->name.find(" (emulates ");
if(pos != std::string::npos)
stick.second->name.erase(pos);
_joyptr->name.erase(pos);
if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor"))
if(BSPF::startsWithIgnoreCase(_joyptr->name, "Stelladaptor"))
{
if(saOrder[saCount] == 1)
{
stick.second->name += " (emulates left joystick port)";
stick.second->type = PhysicalJoystick::JT_STELLADAPTOR_LEFT;
_joyptr->name += " (emulates left joystick port)";
_joyptr->type = PhysicalJoystick::Type::LEFT_STELLADAPTOR;
}
else if(saOrder[saCount] == 2)
{
stick.second->name += " (emulates right joystick port)";
stick.second->type = PhysicalJoystick::JT_STELLADAPTOR_RIGHT;
_joyptr->name += " (emulates right joystick port)";
_joyptr->type = PhysicalJoystick::Type::RIGHT_STELLADAPTOR;
}
saCount++;
}
else if(BSPF::startsWithIgnoreCase(stick.second->name, "2600-daptor"))
else if(BSPF::startsWithIgnoreCase(_joyptr->name, "2600-daptor"))
{
if(saOrder[saCount] == 1)
{
stick.second->name += " (emulates left joystick port)";
stick.second->type = PhysicalJoystick::JT_2600DAPTOR_LEFT;
_joyptr->name += " (emulates left joystick port)";
_joyptr->type = PhysicalJoystick::Type::LEFT_2600DAPTOR;
}
else if(saOrder[saCount] == 2)
{
stick.second->name += " (emulates right joystick port)";
stick.second->type = PhysicalJoystick::JT_2600DAPTOR_RIGHT;
_joyptr->name += " (emulates right joystick port)";
_joyptr->type = PhysicalJoystick::Type::RIGHT_2600DAPTOR;
}
saCount++;
}
@ -263,6 +267,24 @@ void PhysicalJoystickHandler::mapStelladaptors(const string& saport)
myOSystem.settings().setValue("saport", saport);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool PhysicalJoystickHandler::hasStelladaptors() const
{
for(auto& [_id, _joyptr] : mySticks)
{
// remove previously added emulated ports
size_t pos = _joyptr->name.find(" (emulates ");
if(pos != std::string::npos)
_joyptr->name.erase(pos);
if(BSPF::startsWithIgnoreCase(_joyptr->name, "Stelladaptor")
|| BSPF::startsWithIgnoreCase(_joyptr->name, "2600-daptor"))
return true;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Depending on parameters, this method does the following:
// 1. update all events with default (event == Event::NoType, updateDefault == true)
@ -313,7 +335,15 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
switch (mode)
{
case EventMode::kEmulationMode:
if((stick % 2) == 0) // even sticks
{
// A regular joystick defaults to left or right based on the
// stick number being even or odd; 'daptor joysticks request a
// specific port
const bool useLeftMappings =
j->type == PhysicalJoystick::Type::REGULAR ? ((stick % 2) == 0) :
(j->type == PhysicalJoystick::Type::LEFT_STELLADAPTOR ||
j->type == PhysicalJoystick::Type::LEFT_2600DAPTOR);
if(useLeftMappings)
{
// put all controller events into their own mode's mappings
for (const auto& item : DefaultLeftJoystickMapping)
@ -323,7 +353,7 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
for (const auto& item : DefaultLeftKeypadMapping)
setDefaultAction(stick, item, event, EventMode::kKeypadMode, updateDefaults);
}
else // odd sticks
else
{
// put all controller events into their own mode's mappings
for (const auto& item : DefaultRightJoystickMapping)
@ -338,6 +368,7 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
// update running emulation mapping too
enableEmulationMappings();
break;
}
case EventMode::kMenuMode:
for (const auto& item : DefaultMenuMapping)
@ -354,8 +385,8 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even
void PhysicalJoystickHandler::setDefaultMapping(Event::Type event, EventMode mode)
{
eraseMapping(event, mode);
for (auto& i : mySticks)
setStickDefaultMapping(i.first, event, mode);
for (const auto& [_id, _joyptr]: mySticks)
setStickDefaultMapping(_id, event, mode);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -529,24 +560,24 @@ void PhysicalJoystickHandler::eraseMapping(Event::Type event, EventMode mode)
// Otherwise, only reset the given event
if(event == Event::NoType)
{
for (auto& stick : mySticks)
for (auto& [_id, _joyptr]: mySticks)
{
stick.second->eraseMap(mode); // erase all events
_joyptr->eraseMap(mode); // erase all events
if(mode == EventMode::kEmulationMode)
{
stick.second->eraseMap(EventMode::kCommonMode);
stick.second->eraseMap(EventMode::kJoystickMode);
stick.second->eraseMap(EventMode::kPaddlesMode);
stick.second->eraseMap(EventMode::kKeypadMode);
_joyptr->eraseMap(EventMode::kCommonMode);
_joyptr->eraseMap(EventMode::kJoystickMode);
_joyptr->eraseMap(EventMode::kPaddlesMode);
_joyptr->eraseMap(EventMode::kKeypadMode);
}
}
}
else
{
for (auto& stick : mySticks)
for (auto& [_id, _joyptr]: mySticks)
{
stick.second->eraseEvent(event, mode); // only reset the specific event
stick.second->eraseEvent(event, getEventMode(event, mode));
_joyptr->eraseEvent(event, mode); // only reset the specific event
_joyptr->eraseEvent(event, getEventMode(event, mode));
}
}
}
@ -558,9 +589,9 @@ void PhysicalJoystickHandler::saveMapping()
// any changes that have been made during the program run
json mapping = json::array();
for(const auto& i: myDatabase)
for(const auto& [_name, _info]: myDatabase)
{
json map = i.second.joy ? i.second.joy->getMap() : i.second.mapping;
json map = _info.joy ? _info.joy->getMap() : _info.mapping;
if (!map.is_null()) mapping.emplace_back(map);
}
@ -574,19 +605,16 @@ string PhysicalJoystickHandler::getMappingDesc(Event::Type event, EventMode mode
ostringstream buf;
EventMode evMode = getEventMode(event, mode);
for(const auto& s: mySticks)
for(const auto& [_id, _joyptr]: mySticks)
{
uInt32 stick = s.first;
const PhysicalJoystickPtr j = s.second;
if(j)
if(_joyptr)
{
//Joystick mapping / labeling
if(j->joyMap.getEventMapping(event, evMode).size())
if(_joyptr->joyMap.getEventMapping(event, evMode).size())
{
if(buf.str() != "")
buf << ", ";
buf << j->joyMap.getEventMappingDesc(stick, event, evMode);
buf << _joyptr->joyMap.getEventMappingDesc(_id, event, evMode);
}
}
}
@ -819,8 +847,8 @@ void PhysicalJoystickHandler::handleHatEvent(int stick, int hat, int value)
VariantList PhysicalJoystickHandler::database() const
{
VariantList db;
for(const auto& i: myDatabase)
VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1);
for(const auto& [_name, _info]: myDatabase)
VarList::push_back(db, _name, _info.joy ? _info.joy->ID : -1);
return db;
}
@ -830,19 +858,160 @@ ostream& operator<<(ostream& os, const PhysicalJoystickHandler& jh)
{
os << "---------------------------------------------------------" << endl
<< "joy database:" << endl;
for(const auto& i: jh.myDatabase)
os << i.first << endl << i.second << endl << endl;
for(const auto& [_name, _info]: jh.myDatabase)
os << _name << endl << _info << endl << endl;
os << "---------------------" << endl
<< "joy active:" << endl;
for(const auto& i: jh.mySticks)
os << i.first << ": " << *i.second << endl;
for(const auto& [_id, _joyptr]: jh.mySticks)
os << _id << ": " << *_joyptr << endl;
os << "---------------------------------------------------------"
<< endl << endl << endl;
return os;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeDeadzone(int direction)
{
int deadzone = BSPF::clamp(myOSystem.settings().getInt("joydeadzone") + direction,
Joystick::DEAD_ZONE_MIN, Joystick::DEAD_ZONE_MAX);
myOSystem.settings().setValue("joydeadzone", deadzone);
Joystick::setDeadZone(deadzone);
int value = Joystick::deadZoneValue(deadzone);
myOSystem.frameBuffer().showGaugeMessage("Joystick deadzone", std::to_string(value),
value, 3200, 32200);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeAnalogPaddleSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("psense") + direction,
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
myOSystem.settings().setValue("psense", sense);
Paddles::setAnalogSensitivity(sense);
ostringstream ss;
ss << std::round(Paddles::analogSensitivityValue(sense) * 100.F) << "%";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle sensitivity", ss.str(), sense,
Paddles::MIN_ANALOG_SENSE, Paddles::MAX_ANALOG_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changePaddleDejitterAveraging(int direction)
{
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.base") + direction,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
myOSystem.settings().setValue("dejitter.base", dejitter);
Paddles::setDejitterBase(dejitter);
ostringstream ss;
if(dejitter)
ss << dejitter;
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter averaging",
ss.str(), dejitter,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changePaddleDejitterReaction(int direction)
{
int dejitter = BSPF::clamp(myOSystem.settings().getInt("dejitter.diff") + direction,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
myOSystem.settings().setValue("dejitter.diff", dejitter);
Paddles::setDejitterDiff(dejitter);
ostringstream ss;
if(dejitter)
ss << dejitter;
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Analog paddle dejitter reaction",
ss.str(), dejitter,
Paddles::MIN_DEJITTER, Paddles::MAX_DEJITTER);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeDigitalPaddleSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("dsense") + direction,
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
myOSystem.settings().setValue("dsense", sense);
Paddles::setDigitalSensitivity(sense);
ostringstream ss;
if(sense)
ss << sense * 10 << "%";
else
ss << "Off";
myOSystem.frameBuffer().showGaugeMessage("Digital sensitivity",
ss.str(), sense,
Paddles::MIN_DIGITAL_SENSE, Paddles::MAX_DIGITAL_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeMousePaddleSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("msense") + direction,
Paddles::MIN_MOUSE_SENSE, Paddles::MAX_MOUSE_SENSE);
myOSystem.settings().setValue("msense", sense);
Paddles::setMouseSensitivity(sense);
ostringstream ss;
ss << sense * 10 << "%";
myOSystem.frameBuffer().showGaugeMessage("Mouse paddle sensitivity",
ss.str(), sense,
Paddles::MIN_MOUSE_SENSE, Paddles::MAX_MOUSE_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeMouseTrackballSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("tsense") + direction,
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
myOSystem.settings().setValue("tsense", sense);
PointingDevice::setSensitivity(sense);
ostringstream ss;
ss << sense * 10 << "%";
myOSystem.frameBuffer().showGaugeMessage("Mouse trackball sensitivity",
ss.str(), sense,
PointingDevice::MIN_SENSE, PointingDevice::MAX_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalJoystickHandler::changeDrivingSensitivity(int direction)
{
int sense = BSPF::clamp(myOSystem.settings().getInt("dcsense") + direction,
Driving::MIN_SENSE, Driving::MAX_SENSE);
myOSystem.settings().setValue("dcsense", sense);
Driving::setSensitivity(sense);
ostringstream ss;
ss << sense * 10 << "%";
myOSystem.frameBuffer().showGaugeMessage("Driving controller sensitivity",
ss.str(), sense,
Driving::MIN_SENSE, Driving::MAX_SENSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftJoystickMapping = {
// Left joystick (assume buttons zero..two)
@ -956,7 +1125,8 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultCommonMapping = {
PhysicalJoystickHandler::EventMappingArray
PhysicalJoystickHandler::DefaultCommonMapping = {
// valid for all joysticks
//#if defined(RETRON77)
{Event::CmdMenuMode, 3}, // Note: buttons 0..2 are used by controllers!
@ -969,7 +1139,8 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultCommo
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultMenuMapping = {
PhysicalJoystickHandler::EventMappingArray
PhysicalJoystickHandler::DefaultMenuMapping = {
// valid for all joysticks
{Event::UISelect, 0},
{Event::UIOK, 1},

View File

@ -28,7 +28,7 @@ class Event;
#include "EventHandlerConstants.hxx"
#include "PhysicalJoystick.hxx"
#include "Variant.hxx"
#include "json.hxx"
#include "json_lib.hxx"
using PhysicalJoystickPtr = shared_ptr<PhysicalJoystick>;
@ -49,8 +49,8 @@ class PhysicalJoystickHandler
private:
struct StickInfo
{
StickInfo(const nlohmann::json& map = nullptr, PhysicalJoystickPtr stick = nullptr)
: mapping(map), joy(std::move(stick)) {}
explicit StickInfo(nlohmann::json map, PhysicalJoystickPtr stick = nullptr)
: mapping(map), joy{std::move(stick)} {}
nlohmann::json mapping;
PhysicalJoystickPtr joy;
@ -71,6 +71,7 @@ class PhysicalJoystickHandler
bool remove(int id);
bool remove(const string& name);
void mapStelladaptors(const string& saport);
bool hasStelladaptors() const;
void setDefaultMapping(Event::Type type, EventMode mode);
/** define mappings for current controllers */
@ -109,6 +110,15 @@ class PhysicalJoystickHandler
/** Returns a list of pairs consisting of joystick name and associated ID. */
VariantList database() const;
void changeDeadzone(int direction = +1);
void changeAnalogPaddleSensitivity(int direction = +1);
void changePaddleDejitterAveraging(int direction = +1);
void changePaddleDejitterReaction(int direction = +1);
void changeDigitalPaddleSensitivity(int direction = +1);
void changeMousePaddleSensitivity(int direction = +1);
void changeMouseTrackballSensitivity(int direction = +1);
void changeDrivingSensitivity(int direction = +1);
private:
using StickDatabase = std::map<string,StickInfo>;
using StickList = std::map<int, PhysicalJoystickPtr>;

View File

@ -19,7 +19,7 @@
#include "Console.hxx"
#include "EventHandler.hxx"
#include "PKeyboardHandler.hxx"
#include "json.hxx"
#include "json_lib.hxx"
using json = nlohmann::json;
@ -40,8 +40,8 @@ static constexpr int MOD3 = KBDM_ALT;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::PhysicalKeyboardHandler(OSystem& system, EventHandler& handler)
: myOSystem(system),
myHandler(handler)
: myOSystem{system},
myHandler{handler}
{
Int32 version = myOSystem.settings().getInt("event_ver");
bool updateDefaults = false;
@ -74,7 +74,7 @@ void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMap
try {
mapping = json::parse(serializedMapping);
} catch (json::exception) {
} catch (const json::exception&) {
Logger::info("converting legacy keyboard mappings");
mapping = KeyMap::convertLegacyMapping(serializedMapping);
@ -82,7 +82,7 @@ void PhysicalKeyboardHandler::loadSerializedMappings(const string& serializedMap
try {
myKeyMap.loadMapping(mapping, mode);
} catch (json::exception) {
} catch (const json::exception&) {
Logger::error("ignoring bad keyboard mappings");
}
}
@ -480,160 +480,215 @@ void PhysicalKeyboardHandler::handleEvent(StellaKey key, StellaMod mod,
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PhysicalKeyboardHandler::toggleModKeys(bool toggle)
{
bool modCombo = myOSystem.settings().getBool("modcombo");
if(toggle)
{
modCombo = !modCombo;
myKeyMap.enableMod() = modCombo;
myOSystem.settings().setValue("modcombo", modCombo);
}
ostringstream ss;
ss << "Modifier key combos ";
ss << (modCombo ? "enabled" : "disabled");
myOSystem.frameBuffer().showTextMessage(ss.str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalKeyboardHandler::EventMappingArray
PhysicalKeyboardHandler::DefaultCommonMapping = {
{Event::ConsoleSelect, KBDK_F1},
{Event::ConsoleReset, KBDK_F2},
{Event::ConsoleColor, KBDK_F3},
{Event::Console7800Pause, KBDK_F3, MOD3},
{Event::ConsoleLeftDiffA, KBDK_F5},
{Event::ConsoleRightDiffA, KBDK_F7},
{Event::SaveState, KBDK_F9},
{Event::SaveAllStates, KBDK_F9, MOD3},
{Event::PreviousState, KBDK_F10, KBDM_SHIFT},
{Event::NextState, KBDK_F10},
{Event::ToggleAutoSlot, KBDK_F10, MOD3},
{Event::LoadState, KBDK_F11},
{Event::LoadAllStates, KBDK_F11, MOD3},
{Event::TakeSnapshot, KBDK_F12},
#ifdef BSPF_MACOS
{Event::TogglePauseMode, KBDK_P, KBDM_SHIFT | MOD3},
#else
{Event::TogglePauseMode, KBDK_PAUSE},
#endif
{Event::OptionsMenuMode, KBDK_TAB},
{Event::CmdMenuMode, KBDK_BACKSLASH},
{Event::TimeMachineMode, KBDK_T, KBDM_SHIFT},
{Event::DebuggerMode, KBDK_GRAVE},
{Event::ExitMode, KBDK_ESCAPE},
#ifdef BSPF_MACOS
{Event::Quit, KBDK_Q, MOD3},
#else
{Event::Quit, KBDK_Q, KBDM_CTRL},
#endif
{Event::ReloadConsole, KBDK_R, KBDM_CTRL},
{Event::PreviousMultiCartRom, KBDK_R, KBDM_SHIFT | KBDM_CTRL},
{ Event::ConsoleSelect, KBDK_F1 },
{ Event::ConsoleReset, KBDK_F2 },
{ Event::ConsoleColor, KBDK_F3 },
{ Event::Console7800Pause, KBDK_F3, MOD3 },
{ Event::ConsoleLeftDiffA, KBDK_F5 },
{ Event::ConsoleRightDiffA, KBDK_F7 },
{ Event::SaveState, KBDK_F9 },
{ Event::SaveAllStates, KBDK_F9, MOD3 },
{ Event::PreviousState, KBDK_F10, KBDM_SHIFT },
{ Event::NextState, KBDK_F10 },
{ Event::ToggleAutoSlot, KBDK_F10, MOD3 },
{ Event::LoadState, KBDK_F11 },
{ Event::LoadAllStates, KBDK_F11, MOD3 },
{ Event::TakeSnapshot, KBDK_F12 },
#ifdef BSPF_MACOS
{ Event::TogglePauseMode, KBDK_P, KBDM_SHIFT | MOD3 },
#else
{ Event::TogglePauseMode, KBDK_PAUSE },
#endif
{ Event::OptionsMenuMode, KBDK_TAB },
{ Event::CmdMenuMode, KBDK_BACKSLASH },
{ Event::TimeMachineMode, KBDK_T, KBDM_SHIFT },
{ Event::DebuggerMode, KBDK_GRAVE },
{ Event::ExitMode, KBDK_ESCAPE },
#ifdef BSPF_MACOS
{ Event::Quit, KBDK_Q, MOD3 },
#else
{ Event::Quit, KBDK_Q, KBDM_CTRL },
#endif
{ Event::ReloadConsole, KBDK_R, KBDM_CTRL },
{ Event::PreviousMultiCartRom, KBDK_R, KBDM_SHIFT | KBDM_CTRL },
{Event::VidmodeDecrease, KBDK_MINUS, MOD3},
{Event::VidmodeIncrease, KBDK_EQUALS, MOD3},
{Event::VCenterDecrease, KBDK_PAGEUP, MOD3},
{Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3},
{Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3},
{Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3},
{Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_CTRL},
{Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3},
{Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3},
{Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL},
{ Event::VidmodeDecrease, KBDK_MINUS, MOD3 },
{ Event::VidmodeIncrease, KBDK_EQUALS, MOD3 },
{ Event::VCenterDecrease, KBDK_PAGEUP, MOD3 },
{ Event::VCenterIncrease, KBDK_PAGEDOWN, MOD3 },
{ Event::VSizeAdjustDecrease, KBDK_PAGEDOWN, KBDM_SHIFT | MOD3 },
{ Event::VSizeAdjustIncrease, KBDK_PAGEUP, KBDM_SHIFT | MOD3 },
{ Event::ToggleCorrectAspectRatio, KBDK_C, KBDM_CTRL },
{ Event::VolumeDecrease, KBDK_LEFTBRACKET, MOD3 },
{ Event::VolumeIncrease, KBDK_RIGHTBRACKET, MOD3 },
{ Event::SoundToggle, KBDK_RIGHTBRACKET, KBDM_CTRL },
{Event::ToggleFullScreen, KBDK_RETURN, MOD3},
{Event::ToggleAdaptRefresh, KBDK_R, MOD3},
{Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT},
{Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT},
//{Event::VidmodeStd, KBDK_1, MOD3},
//{Event::VidmodeRGB, KBDK_2, MOD3},
//{Event::VidmodeSVideo, KBDK_3, MOD3},
//{Event::VidModeComposite, KBDK_4, MOD3},
//{Event::VidModeBad, KBDK_5, MOD3},
//{Event::VidModeCustom, KBDK_6, MOD3},
{Event::PreviousVideoMode, KBDK_1, KBDM_SHIFT | MOD3},
{Event::NextVideoMode, KBDK_1, MOD3},
{Event::PreviousAttribute, KBDK_2, KBDM_SHIFT | MOD3},
{Event::NextAttribute, KBDK_2, MOD3},
{Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3},
{Event::IncreaseAttribute, KBDK_3, MOD3},
{Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3},
{Event::PhosphorIncrease, KBDK_4, MOD3},
{Event::TogglePhosphor, KBDK_P, MOD3},
{Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3},
{Event::ScanlinesIncrease, KBDK_5, MOD3},
{Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3},
{Event::NextPaletteAttribute, KBDK_9, MOD3},
{Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3},
{Event::PaletteAttributeIncrease, KBDK_0, MOD3},
{Event::ToggleColorLoss, KBDK_L, KBDM_CTRL},
{Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL},
{Event::PaletteIncrease, KBDK_P, KBDM_CTRL},
{ Event::ToggleFullScreen, KBDK_RETURN, MOD3 },
{ Event::ToggleAdaptRefresh, KBDK_R, MOD3 },
{ Event::OverscanDecrease, KBDK_PAGEDOWN, KBDM_SHIFT },
{ Event::OverscanIncrease, KBDK_PAGEUP, KBDM_SHIFT },
//{Event::VidmodeStd, KBDK_1, MOD3},
//{Event::VidmodeRGB, KBDK_2, MOD3},
//{Event::VidmodeSVideo, KBDK_3, MOD3},
//{Event::VidModeComposite, KBDK_4, MOD3},
//{Event::VidModeBad, KBDK_5, MOD3},
//{Event::VidModeCustom, KBDK_6, MOD3},
{ Event::PreviousVideoMode, KBDK_1, KBDM_SHIFT | MOD3 },
{ Event::NextVideoMode, KBDK_1, MOD3 },
{ Event::PreviousAttribute, KBDK_2, KBDM_SHIFT | MOD3 },
{ Event::NextAttribute, KBDK_2, MOD3 },
{ Event::DecreaseAttribute, KBDK_3, KBDM_SHIFT | MOD3 },
{ Event::IncreaseAttribute, KBDK_3, MOD3 },
{ Event::PhosphorDecrease, KBDK_4, KBDM_SHIFT | MOD3 },
{ Event::PhosphorIncrease, KBDK_4, MOD3 },
{ Event::TogglePhosphor, KBDK_P, MOD3 },
{ Event::ScanlinesDecrease, KBDK_5, KBDM_SHIFT | MOD3 },
{ Event::ScanlinesIncrease, KBDK_5, MOD3 },
{ Event::PreviousPaletteAttribute, KBDK_9, KBDM_SHIFT | MOD3 },
{ Event::NextPaletteAttribute, KBDK_9, MOD3 },
{ Event::PaletteAttributeDecrease, KBDK_0, KBDM_SHIFT | MOD3 },
{ Event::PaletteAttributeIncrease, KBDK_0, MOD3 },
{ Event::ToggleColorLoss, KBDK_L, KBDM_CTRL },
{ Event::PaletteDecrease, KBDK_P, KBDM_SHIFT | KBDM_CTRL },
{ Event::PaletteIncrease, KBDK_P, KBDM_CTRL },
{ Event::FormatDecrease, KBDK_F, KBDM_SHIFT | KBDM_CTRL },
{ Event::FormatIncrease, KBDK_F, KBDM_CTRL },
#ifndef BSPF_MACOS
{ Event::PreviousSetting, KBDK_END },
{ Event::NextSetting, KBDK_HOME },
{ Event::PreviousSettingGroup, KBDK_END, KBDM_CTRL },
{ Event::NextSettingGroup, KBDK_HOME, KBDM_CTRL },
#else
// HOME & END keys are swapped on Mac keyboards
{ Event::PreviousSetting, KBDK_HOME },
{ Event::NextSetting, KBDK_END },
{ Event::PreviousSettingGroup, KBDK_HOME, KBDM_CTRL },
{ Event::NextSettingGroup, KBDK_END, KBDM_CTRL },
#endif
{ Event::PreviousSetting, KBDK_KP_1 },
{ Event::NextSetting, KBDK_KP_7 },
{ Event::PreviousSettingGroup, KBDK_KP_1, KBDM_CTRL },
{ Event::NextSettingGroup, KBDK_KP_7, KBDM_CTRL },
{ Event::SettingDecrease, KBDK_PAGEDOWN },
{ Event::SettingDecrease, KBDK_KP_3, KBDM_CTRL },
{ Event::SettingIncrease, KBDK_PAGEUP },
{ Event::SettingIncrease, KBDK_KP_9, KBDM_CTRL },
#ifndef BSPF_MACOS
{Event::PreviousSetting, KBDK_END},
{Event::NextSetting, KBDK_HOME},
{Event::PreviousSettingGroup, KBDK_END, KBDM_CTRL},
{Event::NextSettingGroup, KBDK_HOME, KBDM_CTRL},
#else
// HOME & END keys are swapped on Mac keyboards
{Event::PreviousSetting, KBDK_HOME},
{Event::NextSetting, KBDK_END},
{Event::PreviousSettingGroup, KBDK_HOME, KBDM_CTRL},
{Event::NextSettingGroup, KBDK_END, KBDM_CTRL},
#endif
{Event::PreviousSetting, KBDK_KP_1},
{Event::NextSetting, KBDK_KP_7},
{Event::PreviousSettingGroup, KBDK_KP_1, KBDM_CTRL},
{Event::NextSettingGroup, KBDK_KP_7, KBDM_CTRL},
{Event::SettingDecrease, KBDK_PAGEDOWN},
{Event::SettingDecrease, KBDK_KP_3, KBDM_CTRL},
{Event::SettingIncrease, KBDK_PAGEUP},
{Event::SettingIncrease, KBDK_KP_9, KBDM_CTRL},
{ Event::ToggleInter, KBDK_I, KBDM_CTRL },
{ Event::DecreaseSpeed, KBDK_S, KBDM_SHIFT | KBDM_CTRL },
{ Event::IncreaseSpeed, KBDK_S, KBDM_CTRL },
{ Event::ToggleTurbo, KBDK_T, KBDM_CTRL },
{ Event::ToggleJitter, KBDK_J, MOD3 },
{ Event::ToggleFrameStats, KBDK_L, MOD3 },
{ Event::ToggleTimeMachine, KBDK_T, MOD3 },
{Event::ToggleInter, KBDK_I, KBDM_CTRL},
{Event::DecreaseSpeed, KBDK_S, KBDM_SHIFT | KBDM_CTRL},
{Event::IncreaseSpeed, KBDK_S, KBDM_CTRL },
{Event::ToggleTurbo, KBDK_T, KBDM_CTRL},
{Event::ToggleJitter, KBDK_J, MOD3},
{Event::ToggleFrameStats, KBDK_L, MOD3},
{Event::ToggleTimeMachine, KBDK_T, MOD3},
#ifdef PNG_SUPPORT
{ Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL },
{ Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL },
#endif
#ifdef PNG_SUPPORT
{Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL},
{Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL},
#endif
{ Event::DecreaseDeadzone, KBDK_F1, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncreaseDeadzone, KBDK_F1, KBDM_CTRL },
{ Event::DecAnalogSense, KBDK_F2, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncAnalogSense, KBDK_F2, KBDM_CTRL },
{ Event::DecDejtterAveraging, KBDK_F3, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncDejtterAveraging, KBDK_F3, KBDM_CTRL },
{ Event::DecDejtterReaction, KBDK_F4, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncDejtterReaction, KBDK_F4, KBDM_CTRL },
{ Event::DecDigitalSense, KBDK_F5, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncDigitalSense, KBDK_F5, KBDM_CTRL },
{ Event::DecreaseAutoFire, KBDK_A, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncreaseAutoFire, KBDK_A, KBDM_CTRL },
{ Event::ToggleFourDirections, KBDK_F6, KBDM_CTRL },
{ Event::ToggleKeyCombos, KBDK_F7, KBDM_CTRL },
{ Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL },
{Event::DecreaseAutoFire, KBDK_A, KBDM_SHIFT | KBDM_CTRL},
{Event::IncreaseAutoFire, KBDK_A, KBDM_CTRL },
{Event::HandleMouseControl, KBDK_0, KBDM_CTRL},
{Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL},
{Event::ToggleSAPortOrder, KBDK_1, KBDM_CTRL},
{Event::FormatDecrease, KBDK_F, KBDM_SHIFT | KBDM_CTRL},
{Event::FormatIncrease, KBDK_F, KBDM_CTRL},
{ Event::PrevMouseAsController, KBDK_F8, KBDM_CTRL | KBDM_SHIFT },
{ Event::NextMouseAsController, KBDK_F8, KBDM_CTRL },
{ Event::DecMousePaddleSense, KBDK_F9, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncMousePaddleSense, KBDK_F9, KBDM_CTRL },
{ Event::DecMouseTrackballSense, KBDK_F10, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncMouseTrackballSense, KBDK_F10, KBDM_CTRL },
{ Event::DecreaseDrivingSense, KBDK_F11, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncreaseDrivingSense, KBDK_F11, KBDM_CTRL },
{ Event::PreviousCursorVisbility, KBDK_F12, KBDM_CTRL | KBDM_SHIFT },
{ Event::NextCursorVisbility, KBDK_F12, KBDM_CTRL },
{ Event::ToggleGrabMouse, KBDK_G, KBDM_CTRL },
{Event::ToggleP0Collision, KBDK_Z, KBDM_SHIFT | MOD3},
{Event::ToggleP0Bit, KBDK_Z, MOD3},
{Event::ToggleP1Collision, KBDK_X, KBDM_SHIFT | MOD3},
{Event::ToggleP1Bit, KBDK_X, MOD3},
{Event::ToggleM0Collision, KBDK_C, KBDM_SHIFT | MOD3},
{Event::ToggleM0Bit, KBDK_C, MOD3},
{Event::ToggleM1Collision, KBDK_V, KBDM_SHIFT | MOD3},
{Event::ToggleM1Bit, KBDK_V, MOD3},
{Event::ToggleBLCollision, KBDK_B, KBDM_SHIFT | MOD3},
{Event::ToggleBLBit, KBDK_B, MOD3},
{Event::TogglePFCollision, KBDK_N, KBDM_SHIFT | MOD3},
{Event::TogglePFBit, KBDK_N, MOD3},
{Event::ToggleCollisions, KBDK_COMMA, KBDM_SHIFT | MOD3},
{Event::ToggleBits, KBDK_COMMA, MOD3},
{Event::ToggleFixedColors, KBDK_PERIOD, MOD3},
{ Event::PreviousLeftPort, KBDK_2, KBDM_CTRL | KBDM_SHIFT },
{ Event::NextLeftPort, KBDK_2, KBDM_CTRL },
{ Event::PreviousRightPort, KBDK_3, KBDM_CTRL | KBDM_SHIFT },
{ Event::NextRightPort, KBDK_3, KBDM_CTRL },
{ Event::ToggleSwapPorts, KBDK_4, KBDM_CTRL },
{ Event::ToggleSwapPaddles, KBDK_5, KBDM_CTRL },
{ Event::DecreasePaddleCenterX, KBDK_6, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncreasePaddleCenterX, KBDK_6, KBDM_CTRL },
{ Event::DecreasePaddleCenterY, KBDK_7, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncreasePaddleCenterY, KBDK_7, KBDM_CTRL },
{ Event::PreviousMouseControl, KBDK_0, KBDM_CTRL | KBDM_SHIFT },
{ Event::NextMouseControl, KBDK_0, KBDM_CTRL },
{ Event::DecreaseMouseAxesRange, KBDK_8, KBDM_CTRL | KBDM_SHIFT },
{ Event::IncreaseMouseAxesRange, KBDK_8, KBDM_CTRL },
{Event::RewindPause, KBDK_LEFT, KBDM_SHIFT},
{Event::Rewind1Menu, KBDK_LEFT, MOD3},
{Event::Rewind10Menu, KBDK_LEFT, KBDM_SHIFT | MOD3},
{Event::RewindAllMenu, KBDK_DOWN, MOD3},
{Event::UnwindPause, KBDK_LEFT, KBDM_SHIFT},
{Event::Unwind1Menu, KBDK_RIGHT, MOD3},
{Event::Unwind10Menu, KBDK_RIGHT, KBDM_SHIFT | MOD3},
{Event::UnwindAllMenu, KBDK_UP, MOD3},
{Event::TogglePlayBackMode, KBDK_SPACE, KBDM_SHIFT},
{ Event::ToggleP0Collision, KBDK_Z, KBDM_SHIFT | MOD3 },
{ Event::ToggleP0Bit, KBDK_Z, MOD3 },
{ Event::ToggleP1Collision, KBDK_X, KBDM_SHIFT | MOD3 },
{ Event::ToggleP1Bit, KBDK_X, MOD3 },
{ Event::ToggleM0Collision, KBDK_C, KBDM_SHIFT | MOD3 },
{ Event::ToggleM0Bit, KBDK_C, MOD3 },
{ Event::ToggleM1Collision, KBDK_V, KBDM_SHIFT | MOD3 },
{ Event::ToggleM1Bit, KBDK_V, MOD3 },
{ Event::ToggleBLCollision, KBDK_B, KBDM_SHIFT | MOD3 },
{ Event::ToggleBLBit, KBDK_B, MOD3 },
{ Event::TogglePFCollision, KBDK_N, KBDM_SHIFT | MOD3 },
{ Event::TogglePFBit, KBDK_N, MOD3 },
{ Event::ToggleCollisions, KBDK_COMMA, KBDM_SHIFT | MOD3 },
{ Event::ToggleBits, KBDK_COMMA, MOD3 },
{ Event::ToggleFixedColors, KBDK_PERIOD, MOD3 },
#if defined(RETRON77)
{Event::ConsoleColorToggle, KBDK_F4}, // back ("COLOR","B/W")
{Event::ConsoleLeftDiffToggle, KBDK_F6}, // front ("SKILL P1")
{Event::ConsoleRightDiffToggle, KBDK_F8}, // front ("SKILL P2")
{Event::CmdMenuMode, KBDK_F13}, // back ("4:3","16:9")
{Event::ExitMode, KBDK_BACKSPACE}, // back ("FRY")
#else // defining duplicate keys must be avoided!
{Event::ConsoleBlackWhite, KBDK_F4},
{Event::ConsoleLeftDiffB, KBDK_F6},
{Event::ConsoleRightDiffB, KBDK_F8},
{Event::Fry, KBDK_BACKSPACE},
{ Event::RewindPause, KBDK_LEFT, KBDM_SHIFT },
{ Event::Rewind1Menu, KBDK_LEFT, MOD3 },
{ Event::Rewind10Menu, KBDK_LEFT, KBDM_SHIFT | MOD3 },
{ Event::RewindAllMenu, KBDK_DOWN, MOD3 },
{ Event::UnwindPause, KBDK_LEFT, KBDM_SHIFT },
{ Event::Unwind1Menu, KBDK_RIGHT, MOD3 },
{ Event::Unwind10Menu, KBDK_RIGHT, KBDM_SHIFT | MOD3 },
{ Event::UnwindAllMenu, KBDK_UP, MOD3 },
{ Event::HighScoresMenuMode, KBDK_INSERT },
{ Event::TogglePlayBackMode, KBDK_SPACE, KBDM_SHIFT },
#if defined(RETRON77)
{ Event::ConsoleColorToggle, KBDK_F4 }, // back ("COLOR","B/W")
{ Event::ConsoleLeftDiffToggle, KBDK_F6 }, // front ("SKILL P1")
{ Event::ConsoleRightDiffToggle, KBDK_F8 }, // front ("SKILL P2")
{ Event::CmdMenuMode, KBDK_F13 }, // back ("4:3","16:9")
{ Event::ExitMode, KBDK_BACKSPACE }, // back ("FRY")
#else // defining duplicate keys must be avoided!
{ Event::ConsoleBlackWhite, KBDK_F4 },
{ Event::ConsoleLeftDiffB, KBDK_F6 },
{ Event::ConsoleRightDiffB, KBDK_F8 },
{ Event::Fry, KBDK_BACKSPACE },
#endif
};

View File

@ -79,6 +79,8 @@ class PhysicalKeyboardHandler
/** See comments on KeyMap.myModEnabled for more information. */
bool& useModKeys() { return myKeyMap.enableMod(); }
void toggleModKeys(bool toggle = true);
private:
// Structure used for action menu items

View File

@ -33,7 +33,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PNGLibrary::PNGLibrary(OSystem& osystem)
: myOSystem(osystem)
: myOSystem{osystem}
{
}

View File

@ -22,8 +22,9 @@
#include "PaletteHandler.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PaletteHandler::PaletteHandler(OSystem& system)
: myOSystem(system)
: myOSystem{system}
{
// Load user-defined palette for this ROM
loadUserPalette();
@ -441,7 +442,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing)
if(timing == ConsoleTiming::ntsc)
{
vector2d IQ[NUM_CHROMA];
// YIQ is YUV shifted by 33°
// YIQ is YUV shifted by 33 degrees
constexpr float offset = 33 * BSPF::PI_f / 180;
const float shift = myPhaseNTSC * BSPF::PI_f / 180;
@ -541,7 +542,7 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing)
void PaletteHandler::adjustHueSaturation(int& R, int& G, int& B, float H, float S)
{
// Adapted from http://beesbuzz.biz/code/16-hsv-color-transforms
// (C) J. Fluffy Shagam
// (C) J. Fluffy Shagam
// License: CC BY-SA 4.0
const float su = S * cosf(-H * BSPF::PI_f);
const float sw = S * sinf(-H * BSPF::PI_f);

View File

@ -65,7 +65,7 @@ class PaletteHandler
};
public:
PaletteHandler(OSystem& system);
explicit PaletteHandler(OSystem& system);
/**
Cycle through available palettes.
@ -139,7 +139,7 @@ class PaletteHandler
float y{0.F};
explicit vector2d(float _x = 0.F, float _y = 0.F)
: x(_x), y(_y) { }
: x{_x}, y{_y} { }
};
/**

View File

@ -38,7 +38,7 @@ class PhosphorHandler
@return Averaged value of the two RGB colors
*/
static inline uInt32 getPixel(const uInt32 c, const uInt32 p)
static constexpr uInt32 getPixel(const uInt32 c, const uInt32 p)
{
// Mix current calculated frame with previous displayed frame
const uInt8 rc = static_cast<uInt8>(c >> 16),

View File

@ -87,7 +87,7 @@ bool PhysicalJoystick::setMap(const json& map)
try {
joyMap.loadMapping(entry.value(), eventModeFromJsonName(entry.key()));
} catch (json::exception) {
} catch (const json::exception&) {
Logger::error("ignoring invalid json mapping for " + entry.key());
}

View File

@ -21,7 +21,7 @@
#include "Event.hxx"
#include "EventHandlerConstants.hxx"
#include "JoyMap.hxx"
#include "json.hxx"
#include "json_lib.hxx"
/**
An abstraction of a physical (real) joystick in Stella.
@ -59,17 +59,13 @@ class PhysicalJoystick
int axes, int buttons, int hats, int balls);
private:
// TODO: these are not required anymore, delete or keep for future usage?
enum JoyType {
JT_NONE = 0,
JT_REGULAR = 1,
JT_STELLADAPTOR_LEFT = 2,
JT_STELLADAPTOR_RIGHT = 3,
JT_2600DAPTOR_LEFT = 4,
JT_2600DAPTOR_RIGHT = 5
enum class Type {
REGULAR,
LEFT_STELLADAPTOR, RIGHT_STELLADAPTOR,
LEFT_2600DAPTOR, RIGHT_2600DAPTOR
};
JoyType type{JT_NONE};
Type type{Type::REGULAR};
int ID{-1};
string name{"None"};
int numAxes{0}, numButtons{0}, numHats{0};

View File

@ -32,6 +32,7 @@ namespace Common {
*/
struct Point
{
// FIXME : make this uInt32
Int32 x{0}; //!< The horizontal part of the point
Int32 y{0}; //!< The vertical part of the point

View File

@ -28,8 +28,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
: myOSystem(system),
myStateManager(statemgr)
: myOSystem{system},
myStateManager{statemgr}
{
setup();
}
@ -41,18 +41,15 @@ void RewindManager::setup()
const string& prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr.";
// Work around a bug in XCode 11.2 with -O0 and -O1
const uInt32 maxBufSize = MAX_BUF_SIZE;
// TODO - Add proper bounds checking (define constexpr variables for this)
// Use those bounds in DeveloperDialog too
mySize = std::min<uInt32>(
myOSystem.settings().getInt(prefix + "tm.size"), maxBufSize);
myOSystem.settings().getInt(prefix + "tm.size"), MAX_BUF_SIZE);
if(mySize != myStateList.capacity())
resize(mySize);
myUncompressed = std::min<uInt32>(
myOSystem.settings().getInt(prefix + "tm.uncompressed"), maxBufSize);
myOSystem.settings().getInt(prefix + "tm.uncompressed"), MAX_BUF_SIZE);
myInterval = INTERVAL_CYCLES[0];
for(int i = 0; i < NUM_INTERVALS; ++i)

View File

@ -158,6 +158,7 @@ class RewindManager
uInt64 getFirstCycles() const;
uInt64 getCurrentCycles() const;
uInt64 getLastCycles() const;
uInt64 getInterval() const { return myInterval; }
/**
Get a collection of cycle timestamps, offset from the first one in

View File

@ -40,8 +40,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
: Sound(osystem),
myAudioSettings(audioSettings)
: Sound{osystem},
myAudioSettings{audioSettings}
{
ASSERT_MAIN_THREAD;
@ -273,7 +273,7 @@ void SoundSDL2::adjustVolume(int direction)
if(percent > 0 && !enabled)
{
setEnabled(!enabled);
setEnabled(true);
myOSystem.console().initializeAudio();
}

View File

@ -37,8 +37,8 @@ namespace {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StaggeredLogger::StaggeredLogger(const string& message, Logger::Level level)
: myMessage(message),
myLevel(level)
: myMessage{message},
myLevel{level}
{
}

View File

@ -31,7 +31,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StateManager::StateManager(OSystem& osystem)
: myOSystem(osystem)
: myOSystem{osystem}
{
myRewindManager = make_unique<RewindManager>(myOSystem, *this);
reset();

View File

@ -20,7 +20,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimerManager::TimerManager()
: nextId(no_timer + 1),
: nextId{no_timer + 1},
queue()
{
}

View File

@ -44,8 +44,8 @@ class Variant
public:
Variant() { } // NOLINT
Variant(const string& s) : data(s) { }
Variant(const char* s) : data(s) { }
Variant(const string& s) : data{s} { }
Variant(const char* s) : data{s} { }
Variant(Int32 i) { buf().str(""); buf() << i; data = buf().str(); }
Variant(uInt32 i) { buf().str(""); buf() << i; data = buf().str(); }

View File

@ -105,14 +105,12 @@ VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
Stretch smode, Int32 fsindex, const string& desc,
float zoomLevel, float overscan)
: stretch(smode),
: screenS(sw, sh),
stretch(smode),
description(desc),
zoom(zoomLevel),
fsIndex(fsindex)
{
// First set default size and positioning
screenS = Common::Size(sw, sh);
// Now resize based on windowed/fullscreen mode and stretch factor
if(fsIndex != -1) // fullscreen mode
{

View File

@ -19,9 +19,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ConvolutionBuffer::ConvolutionBuffer(uInt32 size)
: mySize(size)
: myData{make_unique<float[]>(size)},
mySize{size}
{
myData = make_unique<float[]>(mySize);
std::fill_n(myData.get(), mySize, 0.F);
}

View File

@ -20,7 +20,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
HighPass::HighPass(float cutOffFrequency, float frequency)
: myAlpha(1.F / (1.F + 2.F*BSPF::PI_f*cutOffFrequency/frequency))
: myAlpha{1.F / (1.F + 2.F*BSPF::PI_f*cutOffFrequency/frequency)}
{
}

View File

@ -69,12 +69,12 @@ LanczosResampler::LanczosResampler(
// formatFrom.sampleRate / formatTo.sampleRate = M / N
//
// -> we find N from fully reducing the fraction.
myPrecomputedKernelCount(reducedDenominator(formatFrom.sampleRate, formatTo.sampleRate)),
myKernelSize(2 * kernelParameter),
myKernelParameter(kernelParameter),
myHighPassL(HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)),
myHighPassR(HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)),
myHighPass(HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate))
myPrecomputedKernelCount{reducedDenominator(formatFrom.sampleRate, formatTo.sampleRate)},
myKernelSize{2 * kernelParameter},
myKernelParameter{kernelParameter},
myHighPassL{HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)},
myHighPassR{HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)},
myHighPass{HIGH_PASS_CUT_OFF, float(formatFrom.sampleRate)}
{
myPrecomputedKernels = make_unique<float[]>(myPrecomputedKernelCount * myKernelSize);

View File

@ -51,12 +51,11 @@ class Resampler {
public:
Resampler(Format formatFrom, Format formatTo,
const NextFragmentCallback& nextFragmentCallback) :
myFormatFrom(formatFrom),
myFormatTo(formatTo),
myNextFragmentCallback(nextFragmentCallback),
myUnderrunLogger("audio buffer underrun", Logger::Level::INFO)
{}
const NextFragmentCallback& nextFragmentCallback)
: myFormatFrom{formatFrom},
myFormatTo{formatTo},
myNextFragmentCallback{nextFragmentCallback},
myUnderrunLogger{"audio buffer underrun", Logger::Level::INFO} { }
virtual void fillFragment(float* fragment, uInt32 length) = 0;

View File

@ -39,13 +39,11 @@ class SimpleResampler : public Resampler
bool myIsUnderrun{true};
private:
SimpleResampler() = delete;
SimpleResampler(const SimpleResampler&) = delete;
SimpleResampler(SimpleResampler&&) = delete;
SimpleResampler& operator=(const SimpleResampler&) = delete;
SimpleResampler& operator=(const SimpleResampler&&) = delete;
};
#endif // SIMPLE_RESAMPLER_HXX

View File

@ -47,6 +47,7 @@ using uInt64 = uint64_t;
#include <iomanip>
#include <memory>
#include <string>
#include <string_view>
#include <sstream>
#include <cstring>
#include <cctype>
@ -60,6 +61,7 @@ using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::string_view;
using std::istream;
using std::ostream;
using std::fstream;
@ -193,51 +195,54 @@ namespace BSPF
catch(...) { return defaultValue; }
}
// Compare two strings, ignoring case
inline int compareIgnoreCase(const string& s1, const string& s2)
// Convert string with base 16 to integer, using default value on any error
inline int stringToIntBase16(const string& s, const int defaultValue = 0)
{
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
return _stricmp(s1.c_str(), s2.c_str());
#else
return strcasecmp(s1.c_str(), s2.c_str());
#endif
}
inline int compareIgnoreCase(const char* s1, const char* s2)
{
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
return _stricmp(s1, s2);
#else
return strcasecmp(s1, s2);
#endif
try { return std::stoi(s, nullptr, 16); }
catch(...) { return defaultValue; }
}
// Test whether the first string starts with the second one (case insensitive)
inline bool startsWithIgnoreCase(const string& s1, const string& s2)
// Compare two strings (case insensitive)
// Return negative, zero, positive result for <,==,> respectively
static constexpr int compareIgnoreCase(string_view s1, string_view s2)
{
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
return _strnicmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
#else
return strncasecmp(s1.c_str(), s2.c_str(), s2.length()) == 0;
#endif
}
inline bool startsWithIgnoreCase(const char* s1, const char* s2)
{
#if (defined BSPF_WINDOWS || defined __WIN32__) && !defined __GNUG__
return _strnicmp(s1, s2, strlen(s2)) == 0;
#else
return strncasecmp(s1, s2, strlen(s2)) == 0;
#endif
// Only compare up to the length of the shorter string
const auto maxsize = std::min(s1.size(), s2.size());
for(size_t i = 0; i < maxsize; ++i)
if(toupper(s1[i]) != toupper(s2[i]))
return toupper(s1[i]) - toupper(s2[i]);
// Otherwise the length of the string takes priority
return static_cast<int>(s1.size() - s2.size());
}
// Test whether two strings are equal (case insensitive)
inline bool equalsIgnoreCase(const string& s1, const string& s2)
inline constexpr bool equalsIgnoreCase(string_view s1, string_view s2)
{
return compareIgnoreCase(s1, s2) == 0;
return s1.size() == s2.size() ? (compareIgnoreCase(s1, s2) == 0) : false;
}
// Test whether the first string starts with the second one (case insensitive)
inline constexpr bool startsWithIgnoreCase(string_view s1, string_view s2)
{
if(s1.size() >= s2.size())
return compareIgnoreCase(s1.substr(0, s2.size()), s2) == 0;
return false;
}
// Test whether the first string ends with the second one (case insensitive)
inline constexpr bool endsWithIgnoreCase(string_view s1, string_view s2)
{
if(s1.size() >= s2.size())
return compareIgnoreCase(s1.substr(s1.size() - s2.size()), s2) == 0;
return false;
}
// Find location (if any) of the second string within the first,
// starting from 'startpos' in the first string
inline size_t findIgnoreCase(const string& s1, const string& s2, size_t startpos = 0)
static size_t findIgnoreCase(string_view s1, string_view s2, size_t startpos = 0)
{
auto pos = std::search(s1.cbegin()+startpos, s1.cend(),
s2.cbegin(), s2.cend(), [](char ch1, char ch2) {
@ -246,19 +251,8 @@ namespace BSPF
return pos == s1.cend() ? string::npos : pos - (s1.cbegin()+startpos);
}
// Test whether the first string ends with the second one (case insensitive)
inline bool endsWithIgnoreCase(const string& s1, const string& s2)
{
if(s1.length() >= s2.length())
{
const char* end = s1.c_str() + s1.length() - s2.length();
return compareIgnoreCase(end, s2.c_str()) == 0;
}
return false;
}
// Test whether the first string contains the second one (case insensitive)
inline bool containsIgnoreCase(const string& s1, const string& s2)
inline bool containsIgnoreCase(string_view s1, string_view s2)
{
return findIgnoreCase(s1, s2) != string::npos;
}
@ -266,14 +260,14 @@ namespace BSPF
// Test whether the first string matches the second one (case insensitive)
// - the first character must match
// - the following characters must appear in the order of the first string
inline bool matches(const string& s1, const string& s2)
inline bool matches(string_view s1, string_view s2)
{
if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1)))
if(startsWithIgnoreCase(s1, s2.substr(0, 1)))
{
size_t pos = 1;
for(uInt32 j = 1; j < s2.size(); ++j)
{
size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos);
size_t found = findIgnoreCase(s1, s2.substr(j, 1), pos);
if(found == string::npos)
return false;
pos += found + 1;
@ -283,6 +277,27 @@ namespace BSPF
return false;
}
// Modify 'str', replacing all occurrences of 'from' with 'to'
inline void replaceAll(string& str, const string& from, const string& to)
{
if(from.empty()) return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != string::npos)
{
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from',
// like replacing 'x' with 'yx'
}
}
// Trim leading and trailing whitespace from a string
inline string trim(const string& str)
{
string::size_type first = str.find_first_not_of(' ');
return (first == string::npos) ? EmptyString :
str.substr(first, str.find_last_not_of(' ')-first+1);
}
// C++11 way to get local time
// Equivalent to the C-style localtime() function, but is thread-safe
inline std::tm localTime()

View File

@ -1,9 +1,26 @@
//============================================================================
//
// 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-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef JSON_DEFINITIONS_HXX
#define JSON_DEFINITIONS_HXX
#include "EventHandlerConstants.hxx"
#include "Event.hxx"
#include "json.hxx"
#include "json_lib.hxx"
#include "StellaKeys.hxx"
NLOHMANN_JSON_SERIALIZE_ENUM(JoyAxis, {
@ -27,7 +44,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(JoyHatDir, {
{JoyHatDir::LEFT, "left"},
{JoyHatDir::RIGHT, "right"},
{JoyHatDir::UP, "up"}
});
})
NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
{EventMode::kEditMode, "kEditMode"},
@ -39,7 +56,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(EventMode, {
{EventMode::kCompuMateMode, "kCompuMateMode"},
{EventMode::kCommonMode, "kCommonMode"},
{EventMode::kNumModes, "kNumModes"},
});
})
NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::NoType, "NoType"},
@ -69,6 +86,16 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::JoystickOneFire, "JoystickOneFire"},
{Event::JoystickOneFire5, "JoystickOneFire5"},
{Event::JoystickOneFire9, "JoystickOneFire9"},
{Event::JoystickTwoUp, "JoystickTwoUp"},
{Event::JoystickTwoDown, "JoystickTwoDown"},
{Event::JoystickTwoLeft, "JoystickTwoLeft"},
{Event::JoystickTwoRight, "JoystickTwoRight"},
{Event::JoystickTwoFire, "JoystickTwoFire"},
{Event::JoystickThreeUp, "JoystickThreeUp"},
{Event::JoystickThreeDown, "JoystickThreeDown"},
{Event::JoystickThreeLeft, "JoystickThreeLeft"},
{Event::JoystickThreeRight, "JoystickThreeRight"},
{Event::JoystickThreeFire, "JoystickThreeFire"},
{Event::PaddleZeroDecrease, "PaddleZeroDecrease"},
{Event::PaddleZeroIncrease, "PaddleZeroIncrease"},
{Event::PaddleZeroAnalog, "PaddleZeroAnalog"},
@ -160,6 +187,50 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::CompuMateEquals, "CompuMateEquals"},
{Event::CompuMatePlus, "CompuMatePlus"},
{Event::CompuMateSlash, "CompuMateSlash"},
{Event::DecreaseDeadzone, "DecreaseDeadzone"},
{Event::IncreaseDeadzone, "IncreaseDeadzone"},
{Event::DecAnalogSense, "DecAnalogSense"},
{Event::IncAnalogSense, "IncAnalogSense"},
{Event::DecDejtterAveraging, "DecDejtterAveraging"},
{Event::IncDejtterAveraging, "IncDejtterAveraging"},
{Event::DecDejtterReaction, "DecDejtterReaction"},
{Event::IncDejtterReaction, "IncDejtterReaction"},
{Event::DecDigitalSense, "DecDigitalSense"},
{Event::IncDigitalSense, "IncDigitalSense"},
{Event::DecreaseAutoFire, "DecreaseAutoFire"},
{Event::IncreaseAutoFire, "IncreaseAutoFire"},
{Event::ToggleFourDirections, "ToggleFourDirections"},
{Event::ToggleKeyCombos, "ToggleKeyCombos"},
{Event::ToggleSAPortOrder, "ToggleSAPortOrder"},
{Event::PrevMouseAsController, "PrevMouseAsController"},
{Event::NextMouseAsController, "NextMouseAsController"},
{Event::DecMousePaddleSense, "DecMousePaddleSense"},
{Event::IncMousePaddleSense, "IncMousePaddleSense"},
{Event::DecMouseTrackballSense, "DecMouseTrackballSense"},
{Event::IncMouseTrackballSense, "IncMouseTrackballSense"},
{Event::DecreaseDrivingSense, "DecreaseDrivingSense"},
{Event::IncreaseDrivingSense, "IncreaseDrivingSense"},
{Event::PreviousCursorVisbility, "PreviousCursorVisbility"},
{Event::NextCursorVisbility, "NextCursorVisbility"},
{Event::ToggleGrabMouse, "ToggleGrabMouse"},
{Event::PreviousLeftPort, "PreviousLeftPort"},
{Event::NextLeftPort, "NextLeftPort"},
{Event::PreviousRightPort, "PreviousRightPort"},
{Event::NextRightPort, "NextRightPort"},
{Event::ToggleSwapPorts, "ToggleSwapPorts"},
{Event::ToggleSwapPaddles,"ToggleSwapPaddles"},
{Event::DecreasePaddleCenterX, "DecreasePaddleCenterX"},
{Event::IncreasePaddleCenterX, "IncreasePaddleCenterX"},
{Event::DecreasePaddleCenterY, "DecreasePaddleCenterY"},
{Event::IncreasePaddleCenterY, "IncreasePaddleCenterY"},
{Event::PreviousMouseControl, "PreviousMouseControl"},
{Event::NextMouseControl, "NextMouseControl"},
{Event::DecreaseMouseAxesRange, "DecreaseMouseAxesRange"},
{Event::IncreaseMouseAxesRange, "IncreaseMouseAxesRange"},
{Event::Combo1, "Combo1"},
{Event::Combo2, "Combo2"},
{Event::Combo3, "Combo3"},
@ -192,8 +263,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::UIPrevDir, "UIPrevDir"},
{Event::UITabPrev, "UITabPrev"},
{Event::UITabNext, "UITabNext"},
{Event::HandleMouseControl, "HandleMouseControl"},
{Event::ToggleGrabMouse, "ToggleGrabMouse"},
{Event::MouseAxisXMove, "MouseAxisXMove"},
{Event::MouseAxisYMove, "MouseAxisYMove"},
{Event::MouseAxisXValue, "MouseAxisXValue"},
@ -207,6 +276,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::StartPauseMode, "StartPauseMode"},
{Event::OptionsMenuMode, "OptionsMenuMode"},
{Event::CmdMenuMode, "CmdMenuMode"},
{Event::HighScoresMenuMode, "HighScoresMenuMode"},
{Event::DebuggerMode, "DebuggerMode"},
{Event::ExitMode, "ExitMode"},
{Event::TakeSnapshot, "TakeSnapshot"},
@ -286,7 +356,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::ToggleBits, "ToggleBits"},
{Event::ToggleFixedColors, "ToggleFixedColors"},
{Event::ToggleFrameStats, "ToggleFrameStats"},
{Event::ToggleSAPortOrder, "ToggleSAPortOrder"},
{Event::ExitGame, "ExitGame"},
{Event::SettingDecrease, "SettingDecrease"},
{Event::SettingIncrease, "SettingIncrease"},
@ -301,16 +370,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Event::Type, {
{Event::IncreaseAutoFire, "IncreaseAutoFire"},
{Event::DecreaseSpeed, "DecreaseSpeed"},
{Event::IncreaseSpeed, "IncreaseSpeed"},
{Event::JoystickTwoUp, "JoystickTwoUp"},
{Event::JoystickTwoDown, "JoystickTwoDown"},
{Event::JoystickTwoLeft, "JoystickTwoLeft"},
{Event::JoystickTwoRight, "JoystickTwoRight"},
{Event::JoystickTwoFire, "JoystickTwoFire"},
{Event::JoystickThreeUp, "JoystickThreeUp"},
{Event::JoystickThreeDown, "JoystickThreeDown"},
{Event::JoystickThreeLeft, "JoystickThreeLeft"},
{Event::JoystickThreeRight, "JoystickThreeRight"},
{Event::JoystickThreeFire, "JoystickThreeFire"},
{Event::ToggleCorrectAspectRatio, "ToggleCorrectAspectRatio"},
{Event::MoveLeftChar, "MoveLeftChar"},
{Event::MoveRightChar, "MoveRightChar"},

View File

@ -123,11 +123,11 @@ void parseCommandLine(int ac, char* av[],
#if 0
cout << "Global opts:" << endl;
for(const auto& x: globalOpts)
cout << " -> " << x.first << ": " << x.second << endl;
for(const auto& [key, value]: globalOpts)
cout << " -> " << key << ": " << value << endl;
cout << "Local opts:" << endl;
for(const auto& x: localOpts)
cout << " -> " << x.first << ": " << x.second << endl;
for(const auto& [key, value]: localOpts)
cout << " -> " << key << ": " << value << endl;
#endif
}

View File

@ -9,6 +9,7 @@ MODULE_OBJS := \
src/common/FBSurfaceSDL2.o \
src/common/FpsMeter.o \
src/common/FSNodeZIP.o \
src/common/HighScoresManager.o \
src/common/JoyMap.o \
src/common/KeyMap.o \
src/common/Logger.o \

View File

@ -18,18 +18,9 @@
#include "KeyValueRepositoryConfigfile.hxx"
#include "Logger.hxx"
namespace {
string trim(const string& str)
{
string::size_type first = str.find_first_not_of(' ');
return (first == string::npos) ? EmptyString :
str.substr(first, str.find_last_not_of(' ')-first+1);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyValueRepositoryConfigfile::KeyValueRepositoryConfigfile(const FilesystemNode& file)
: myFile(file)
: myFile{file}
{
}
@ -67,8 +58,8 @@ std::map<string, Variant> KeyValueRepositoryConfigfile::load()
continue;
// Split the line into key/value pairs and trim any whitespace
key = trim(line.substr(0, equalPos));
value = trim(line.substr(equalPos + 1, line.length() - key.length() - 1));
key = BSPF::trim(line.substr(0, equalPos));
value = BSPF::trim(line.substr(equalPos + 1, line.length() - key.length() - 1));
// Skip absent key
if(key.length() == 0)
@ -100,8 +91,8 @@ void KeyValueRepositoryConfigfile::save(const std::map<string, Variant>& values)
<< ";" << endl;
// Write out each of the key and value pairs
for(const auto& pair: values)
out << pair.first << " = " << pair.second << endl;
for(const auto& [key, value]: values)
out << key << " = " << value << endl;
try
{

View File

@ -22,10 +22,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyValueRepositorySqlite::KeyValueRepositorySqlite(
SqliteDatabase& db,
const string& tableName
) : myTableName(tableName),
myDb(db)
SqliteDatabase& db, const string& tableName)
: myTableName{tableName},
myDb{db}
{
}

View File

@ -20,12 +20,11 @@
#include "SqliteError.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SettingsDb::SettingsDb(
const string& databaseDirectory,
const string& databaseName
) : myDatabaseDirectory(databaseDirectory),
myDatabaseName(databaseName)
{}
SettingsDb::SettingsDb(const string& databaseDirectory, const string& databaseName)
: myDatabaseDirectory{databaseDirectory},
myDatabaseName{databaseName}
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SettingsDb::initialize()

View File

@ -30,7 +30,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteDatabase::SqliteDatabase(const string& databaseDirectory,
const string& databaseName)
: myDatabaseFile(databaseDirectory + SEPARATOR + databaseName + ".sqlite3")
: myDatabaseFile{databaseDirectory + SEPARATOR + databaseName + ".sqlite3"}
{
}

View File

@ -19,7 +19,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteStatement::SqliteStatement(sqlite3* handle, string sql)
: myHandle(handle)
: myHandle{handle}
{
if (sqlite3_prepare_v2(handle, sql.c_str(), -1, &myStmt, nullptr) != SQLITE_OK)
throw SqliteError(handle);

View File

@ -20,7 +20,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SqliteTransaction::SqliteTransaction(SqliteDatabase& db)
: myDb(db)
: myDb{db}
{
myDb.exec("BEGIN TRANSACTION");
}

View File

@ -21,8 +21,8 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BilinearBlitter::BilinearBlitter(FBBackendSDL2& fb, bool interpolate)
: myFB(fb),
myInterpolate(interpolate)
: myFB{fb},
myInterpolate{interpolate}
{
}

View File

@ -21,7 +21,8 @@
#include "BilinearBlitter.hxx"
#include "QisBlitter.hxx"
unique_ptr<Blitter> BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
unique_ptr<Blitter>
BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
{
if (!fb.isInitialized()) {
throw runtime_error("BlitterFactory requires an initialized framebuffer!");

View File

@ -21,7 +21,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
QisBlitter::QisBlitter(FBBackendSDL2& fb)
: myFB(fb)
: myFB{fb}
{
}

374
src/common/stella.pro Normal file
View File

@ -0,0 +1,374 @@
"Cart.MD5" "05215b73ec33b502449ee726ac6b201f"
"Cart.Name" "draconian_20171013_RC6"
"Display.Phosphor" "YES"
"Cart.Variations" "4"
"Cart.Formats" "8,0,B,0,B,1,SECT.,D,1,VARIATIONS_ARE_DIFFICULTY_LEVEL"
"Cart.Addresses" "177B,177A,1779,1778,811,1780"
""
"Cart.MD5" "081e2c114c9c20b61acf25fc95c71bf4"
"Cart.Manufacturer" "Parker Brothers, Ed English, David Lamkins"
"Cart.ModelNo" "PB5300"
"Cart.Name" "Frogger (1982) (Parker Bros)"
"Display.Phosphor" "YES"
"Cart.Variations" "6"
"Cart.Addresses" "CC,CE,DD,E6"
""
"Cart.MD5" "136f75c4dd02c29283752b7e5799f978"
"Cart.Manufacturer" "Atari, Dan Hitchens - Sears"
"Cart.ModelNo" "CX2650 - 49-75168"
"Cart.Name" "Berzerk (1982) (Atari)"
"Cart.Rarity" "Common"
"Cart.Variations" "12"
"Cart.Formats" "6"
"Cart.Addresses" "DD,DE,DF,80"
""
"Cart.MD5" "137373599e9b7bf2cf162a102eb5927f"
"Cart.Manufacturer" "AtariAge, Joe Grand"
"Cart.Name" "Ultra SCSIcide (SCSIcide 2.0)"
"Controller.Left" "PADDLES"
"Cart.Formats" "6,0,H"
"Cart.Addresses" "DC,DD,DE"
""
"Cart.MD5" "211774f4c5739042618be8ff67351177"
"Cart.Manufacturer" "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker"
"Cart.ModelNo" "CX2684"
"Cart.Name" "Galaxian (1983) (Atari)"
"Display.Phosphor" "YES"
"Cart.Variations" "9"
"Cart.Formats" "6,0,B,0,B,0,WAVE"
"Cart.Addresses" "AC,AD,AE,B3,AF"
""
"Cart.MD5" "240bfbac5163af4df5ae713985386f92"
"Cart.Manufacturer" "Activision, Steve Cartwright"
"Cart.ModelNo" "AX-022"
"Cart.Name" "Seaquest (1983) (Activision)"
"Cart.Formats" "6,0,B,0,B,0,_,B,0,HIGH_SCORE_IS_FROM_CURRENT_PLAYER"
"Cart.Addresses" "B8,B9,BA"
""
"Cart.MD5" "278f14887d601b5e5b620f1870bc09f6"
"Cart.Manufacturer" "Thomas Jentzsch"
"Cart.Name" "SWOOPS! (v0.96) (TJ)"
"Cart.Note" "Uses the Joystick (L) and Paddle (R) Controllers"
"Cart.Rarity" "Homebrew"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,0,B,1"
"Cart.Addresses" "FD,FE,FF,FC"
""
"Cart.MD5" "2903896d88a341511586d69fcfc20f7d"
"Cart.Manufacturer" "Activision, David Crane"
"Cart.ModelNo" "AX-014, AX-014-04"
"Cart.Name" "Grand Prix (1982) (Activision)"
"Cart.Variations" "4"
"Cart.Formats" "5,0,B,1,B,1,_,B,0,TIME/SCORE_SHOWS_EXTRA_DIGIT"
"Cart.Addresses" "EB,EC,ED,80"
""
"Cart.MD5" "2a0ba55e56e7a596146fa729acf0e109"
"Cart.Manufacturer" "Activision, Bob Whitehead"
"Cart.ModelNo" "AG-019"
"Cart.Name" "Sky Jinks (1982) (Activision)"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,1,B,1"
"Cart.Addresses" "9E,A6,A2,99"
""
"Cart.MD5" "2bb9f4686f7e08c5fcc69ec1a1c66fe7"
"Cart.Manufacturer" "Atari - GCC, John Allred, Mike Feinstein"
"Cart.ModelNo" "CX2688"
"Cart.Name" "Jungle Hunt (1983) (Atari)"
"Cart.Variations" "2"
"Cart.Formats" "6,0,B,0,B,1"
"Cart.Addresses" "85,84,83,8B"
""
"Cart.MD5" "318a9d6dda791268df92d72679914ac3"
"Cart.Manufacturer" "Activision, Steve Cartwright"
"Cart.ModelNo" "AX-017, AX-017-04"
"Cart.Name" "MegaMania (1982) (Activision)"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,0,B,1"
"Cart.Addresses" "DB,DC,DD,80"
""
"Cart.MD5" "36b20c427975760cb9cf4a47e41369e4"
"Cart.Manufacturer" "Coleco - Woodside Design Associates - Imaginative Systems Software, Garry Kitchen"
"Cart.ModelNo" "2451"
"Cart.Name" "Donkey Kong (1982) (Coleco)"
"Cart.Formats" "6,2"
"Cart.Addresses" "87,88"
""
"Cart.MD5" "3a2e2d0c6892aa14544083dfb7762782"
"Cart.Manufacturer" "Atari, Rob Fulop - Sears"
"Cart.ModelNo" "CX2638 - 49-75166"
"Cart.Name" "Missile Command (1981) (Atari)"
"Display.Phosphor" "YES"
"Cart.Variations" "34"
"Cart.Formats" "6"
"Cart.Addresses" "F3,F1,EF,E9"
""
"Cart.MD5" "3e90cf23106f2e08b2781e41299de556"
"Cart.Manufacturer" "Activision, David Crane"
"Cart.ModelNo" "AX-018, AX-018-04"
"Cart.Name" "Pitfall! (1982) (Activision)"
"Cart.Note" "Pitfall Harry's Jungle Adventure (Jungle Runner)"
"Cart.Formats" "6"
"Cart.Addresses" "D5,D6,D7"
""
"Cart.MD5" "4ca73eb959299471788f0b685c3ba0b5"
"Cart.Manufacturer" "Activision, Steve Cartwright"
"Cart.ModelNo" "AX-031"
"Cart.Name" "Frostbite (1983) (Activision)"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,0,B,1,LEVEL,B,1"
"Cart.Addresses" "C8,C9,CA,80,CB"
""
"Cart.MD5" "515046e3061b7b18aa3a551c3ae12673"
"Cart.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito"
"Cart.ModelNo" "CX2692"
"Cart.Name" "Moon Patrol (1983) (Atari)"
"Cart.Variations" "6"
"Cart.Formats" "6,0,B,0,B,1"
"Cart.Addresses" "EA,EB,EC,F9"
""
"Cart.MD5" "541cac55ebcf7891d9d51c415922303f"
"Cart.Name" "SF2_20131217_RC8_NTSC"
"Display.Phosphor" "YES"
"Cart.Formats" "8,0,B,0,B,0,LEVEL,D,1"
"Cart.Addresses" "1CF7,1CF6,1CF5,1CF4,0,18AC"
""
"Cart.MD5" "6dda84fb8e442ecf34241ac0d1d91d69"
"Cart.Manufacturer" "Atari - GCC, Douglas B. Macrae"
"Cart.ModelNo" "CX2677"
"Cart.Name" "Dig Dug (1983) (Atari)"
"Cart.Variations" "2"
"Cart.Formats" "4,0,B,0,B,1,_,B,0,VARIATION_1_IS_EASY;_2_IS_NORMAL"
"Cart.Addresses" "F0FE,F0FD,80"
""
"Cart.MD5" "72ffbef6504b75e69ee1045af9075f66"
"Cart.Manufacturer" "Atari, Richard Maurer - Sears"
"Cart.ModelNo" "CX2632 - 49-75153"
"Cart.Name" "Space Invaders (1980) (Atari)"
"Cart.Variations" "112"
"Cart.Formats" "4,0,B,0,D,1,_,B,0,ONLY_PLAYER_1_SUPPORTED"
"Cart.Addresses" "E6,E8,DC"
""
"Cart.MD5" "77057d9d14b99e465ea9e29783af0ae3"
"Cart.Manufacturer" "Activision, David Crane"
"Cart.ModelNo" "AG-001"
"Cart.Name" "Dragster (1980) (Activision)"
"Cart.Note" "AKA Drag Strip"
"Cart.Formats" "4,0,B,1,B,1"
"Cart.Addresses" "B3,B5,80,0"
""
"Cart.MD5" "7e52a95074a66640fcfde124fffd491a"
"Cart.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek"
"Cart.ModelNo" "CX2673"
"Cart.Name" "Phoenix (1983) (Atari)"
"Cart.Formats" "6"
"Cart.Addresses" "C9,C8,C7"
""
"Cart.MD5" "87e79cd41ce136fd4f72cc6e2c161bee"
"Cart.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker"
"Cart.ModelNo" "CX2675"
"Cart.Name" "Ms. Pac-Man (1983) (Atari)"
"Display.Phosphor" "YES"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,0,B,1,_,D,1,VARS_VALID_AT_GAME_OVER;_CHERRIES_=_VAR_#4"
"Cart.Addresses" "FA,F9,F8,F7,0"
""
"Cart.MD5" "91c2098e88a6b13f977af8c003e0bca5"
"Cart.Manufacturer" "Atari - GCC"
"Cart.ModelNo" "CX2676"
"Cart.Name" "Centipede (1983) (Atari)"
"Cart.Formats" "6,0,B,0,B,0,_,B,0,VARIATIONS_CANNOT_BE_DEFINED"
"Cart.Addresses" "F4,F5,F6"
""
"Cart.MD5" "91f0a708eeb93c133e9672ad2c8e0429"
"Cart.Name" "Oystron (V2.9) (Piero Cavina) (PD)"
"Cart.Rarity" "New Release"
"Cart.Variations" "3"
"Cart.Formats" "5,1,B,0,B,1"
"Cart.Addresses" "D4,D3,E5"
""
"Cart.MD5" "94b92a882f6dbaa6993a46e2dcc58402"
"Cart.Manufacturer" "Activision, Larry Miller"
"Cart.ModelNo" "AX-026, AX-026-04"
"Cart.Name" "Enduro (1983) (Activision)"
"Cart.Formats" "6,0,B,0,B,0,DAY"
"Cart.Addresses" "AA,A9,A8,0,AD"
""
"Cart.MD5" "9ad36e699ef6f45d9eb6c4cf90475c9f"
"Cart.Manufacturer" "Imagic, Dennis Koble"
"Cart.ModelNo" "720103-1A, 720103-1B, IA3203, IX-010-04"
"Cart.Name" "Atlantis (1982) (Imagic)"
"Cart.Note" "AKA Lost City of Atlantis"
"Cart.Rarity" "Uncommon"
"Cart.Variations" "4"
"Cart.Formats" "6,2,B,0,B,1"
"Cart.Addresses" "A3,A2,8D"
""
"Cart.MD5" "ab5bf1ef5e463ad1cbb11b6a33797228"
"Cart.Manufacturer" "Imagic, Rob Fulop"
"Cart.ModelNo" "720104-1A, 720104-1B, IA3204"
"Cart.Name" "Cosmic Ark (1982) (Imagic)"
"Cart.Variations" "6"
"Cart.Formats" "6"
"Cart.Addresses" "AE,B0,B2,BC"
""
"Cart.MD5" "ac7c2260378975614192ca2bc3d20e0b"
"Cart.Manufacturer" "Activision, David Crane"
"Cart.ModelNo" "AG-930-04, AZ-030"
"Cart.Name" "Decathlon (1983) (Activision)"
"Cart.Rarity" "Rare"
"Cart.Variations" "10"
"Cart.Formats" "4,0,B,0,D,1,_,B,0,DECATHLON_&_100M_DASH_SHARE_VARIATION_1"
"Cart.Addresses" "95,96,80,0"
""
"Cart.MD5" "be929419902e21bd7830a7a7d746195d"
"Cart.Manufacturer" "Activision, Garry Kitchen"
"Cart.ModelNo" "AX-025, AX-025-04"
"Cart.Name" "Keystone Kapers (1983) (Activision)"
"Cart.Formats" "6"
"Cart.Addresses" "9A,9B,9C"
""
"Cart.MD5" "c1cb228470a87beb5f36e90ac745da26"
"Cart.Manufacturer" "Activision, Bob Whitehead"
"Cart.ModelNo" "AX-015, AX-015-04"
"Cart.Name" "Chopper Command (1982) (Activision)"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,0,B,1"
"Cart.Addresses" "EC,EE,F0,E0"
""
"Cart.MD5" "c5930d0e8cdae3e037349bfa08e871be"
"Cart.Manufacturer" "Atari, Howard Scott Warshaw - Sears"
"Cart.ModelNo" "CX2655 - 49-75167"
"Cart.Name" "Yars' Revenge (1982) (Atari)"
"Display.Phosphor" "YES"
"Cart.Variations" "8"
"Cart.Formats" "6,0,B,0,B,1,_,B,0,VARIATIONS_ARE_LARGER_BY_1"
"Cart.Addresses" "E0,E1,E2,80"
""
"Cart.MD5" "c6556e082aac04260596b4045bc122de"
"Cart.Manufacturer" "Atari - GCC, Dave Payne"
"Cart.ModelNo" "CX2669"
"Cart.Name" "Vanguard (1983) (Atari)"
"Cart.Formats" "6,0,B,0,B,0,_,B,0,SCORE_IS_FOR_CURRENT_PLAYER"
"Cart.Addresses" "99,98,97"
""
"Cart.MD5" "ccbd36746ed4525821a8083b0d6d2c2c"
"Cart.Manufacturer" "Atari, Brad Stewart - Sears"
"Cart.ModelNo" "CX2649, 49-75163"
"Cart.Name" "Asteroids (1981) (Atari) [no copyright]"
"Cart.Rarity" "Common"
"Display.Phosphor" "YES"
"Cart.Variations" "66"
"Cart.Formats" "5,1,H,1,D,0,_,B,0,VARIATIONS_>_32_DIFFER_BY_1"
"Cart.Addresses" "BD,BE,80"
""
"Cart.MD5" "d69559f9c9dc6ef528d841bf9d91b275"
"Cart.Manufacturer" "Activision, Alan Miller"
"Cart.ModelNo" "AX-016"
"Cart.Name" "StarMaster (1982) (Activision)"
"Cart.Note" "Use Color/BW switch to change between galactic chart and front views"
"Cart.Variations" "4"
"Cart.Formats" "4,0,B,0,B,1,_,B,0,SCORE_ONLY_CALCULATED_WHEN_GAME_IS_OVER"
"Cart.Addresses" "C1,C2,80"
""
"Cart.MD5" "dd7884b4f93cab423ac471aa1935e3df"
"Cart.Manufacturer" "Atari, Brad Stewart - Sears"
"Cart.ModelNo" "CX2649, 49-75163"
"Cart.Name" "Asteroids (1981) (Atari)"
"Cart.Variations" "66"
"Cart.Formats" "5,1,H,1,D,0,_,B,0,VARIATIONS_>_32_DIFFER_BY_1"
"Cart.Addresses" "BD,BE,80"
""
"Cart.MD5" "dde55d9868911407fe8b3fefef396f00"
"Cart.Name" "Seawolf (2004) (Xype, Manuel Rotschkar)"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,0,B,0,_,B,0,USER_DEFINED_VARIATION_BASED_ON_SWITCHES"
"Cart.Addresses" "90,91,92,0,0"
""
"Cart.MD5" "f0e0addc07971561ab80d9abe1b8d333"
"Cart.Manufacturer" "Imagic, Rob Fulop"
"Cart.ModelNo" "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04"
"Cart.Name" "Demon Attack (1982) (Imagic)"
"Cart.Note" "AKA Death from Above"
"Cart.Variations" "10"
"Cart.Formats" "6,0,B,0,B,0,WAVE,B,1"
"Cart.Addresses" "81,83,85,EA,80"
""
"Cart.MD5" "f1489e27a4539a0c6c8529262f9f7e18"
"Cart.Manufacturer" "Champ Games"
"Cart.ModelNo" "CG-01-P"
"Cart.Name" "Lady Bug (PAL60)"
"Cart.Rarity" "Homebrew"
"Console.RightDiff" "A"
"Display.Format" "PAL60"
"Display.Phosphor" "YES"
"Cart.Variations" "3"
"Cart.Formats" "6,0,B,0,B,1,PART,D,1"
"Cart.Addresses" "8E,8D,8C,8A,89"
""
"Cart.MD5" "f34f08e5eb96e500e851a80be3277a56"
"Cart.Manufacturer" "Atari, Brad Stewart - Sears"
"Cart.ModelNo" "CX2622 - 6-99813, 49-75107"
"Cart.Name" "Breakout (1978) (Atari)"
"Cart.Note" "Uses the Paddle Controllers"
"Controller.MouseAxis" "01 60"
"Cart.Formats" "3,0,B,0,B,0,_,B,0,VARIATIONS_CANNOT_BE_DEFINED"
"Cart.Addresses" "CE,CD"
""
"Cart.MD5" "f8240e62d8c0a64a61e19388414e3104"
"Cart.Manufacturer" "Activision, Steve Cartwright"
"Cart.ModelNo" "AX-013"
"Cart.Name" "Barnstorming (1982) (Activision)"
"Cart.Rarity" "Uncommon"
"Cart.Variations" "4"
"Cart.Formats" "6,0,B,1,B,1"
"Cart.Addresses" "B5,B6,B7,80"
""
"Cart.MD5" "fca4a5be1251927027f2c24774a02160"
"Cart.Manufacturer" "Activision, John Van Ryzin"
"Cart.ModelNo" "AZ-036-04"
"Cart.Name" "H.E.R.O. (1984) (Activision)"
"Cart.Variations" "5"
"Cart.Formats" "6,0,B,0,B,1,LEVEL,D,1"
"Cart.Addresses" "B7,B8,B9,80,F5"
""

View File

@ -232,7 +232,7 @@ class AtariNTSC
}
// Common ntsc macros
static inline constexpr void ATARI_NTSC_CLAMP( uInt32& io, uInt32 shift ) {
static constexpr void ATARI_NTSC_CLAMP( uInt32& io, uInt32 shift ) {
uInt32 sub = io >> (9-(shift)) & atari_ntsc_clamp_mask;
uInt32 clamp = atari_ntsc_clamp_add - sub;
io |= clamp;
@ -240,31 +240,31 @@ class AtariNTSC
io &= clamp;
}
static inline constexpr void RGB_TO_YIQ(float r, float g, float b,
static constexpr void RGB_TO_YIQ(float r, float g, float b,
float& y, float& i, float& q) {
y = r * 0.299F + g * 0.587F + b * 0.114F;
i = r * 0.595716F - g * 0.274453F - b * 0.321263F;
q = r * 0.211456F - g * 0.522591F + b * 0.311135F;
}
static inline constexpr void YIQ_TO_RGB(float y, float i, float q,
static constexpr void YIQ_TO_RGB(float y, float i, float q,
const float* to_rgb, int& ir, int& ig, int& ib) {
ir = static_cast<int>(y + to_rgb[0] * i + to_rgb[1] * q);
ig = static_cast<int>(y + to_rgb[2] * i + to_rgb[3] * q);
ib = static_cast<int>(y + to_rgb[4] * i + to_rgb[5] * q);
}
static inline constexpr uInt32 PACK_RGB( int r, int g, int b ) {
static constexpr uInt32 PACK_RGB( int r, int g, int b ) {
return r << 21 | g << 11 | b << 1;
}
// Converted from C-style macros; I don't even pretend to understand the logic here :)
static inline constexpr int PIXEL_OFFSET1( int ntsc, int scaled ) {
static constexpr int PIXEL_OFFSET1( int ntsc, int scaled ) {
return (kernel_size / 2 + ((ntsc) - (scaled) / rescale_out * rescale_in) +
((((scaled) + rescale_out * 10) % rescale_out) != 0) +
(rescale_out - (((scaled) + rescale_out * 10) % rescale_out)) % rescale_out +
(kernel_size * 2 * (((scaled) + rescale_out * 10) % rescale_out)));
}
static inline constexpr int PIXEL_OFFSET2( int ntsc ) {
static constexpr int PIXEL_OFFSET2( int ntsc ) {
return 1.0F - (((ntsc) + 100) & 2);
}

View File

@ -192,7 +192,7 @@ void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NTSCFilter::setCustomAdjustables(Adjustable& adjustable)
void NTSCFilter::setCustomAdjustables(const Adjustable& adjustable)
{
#ifdef BLARGG_PALETTE
//myCustomSetup.hue = scaleFrom100(adjustable.hue);

View File

@ -90,7 +90,7 @@ class NTSCFilter
// Set custom adjustables to given values
// Values will be scaled to 0 - 100 range, independent of how
// they're actually stored internally
void setCustomAdjustables(Adjustable& adjustable);
void setCustomAdjustables(const Adjustable& adjustable);
// The following methods cycle through each custom adjustable
// They are used in conjunction with the increase/decrease

View File

@ -30,12 +30,12 @@
class BreakpointMap
{
private:
static const uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then)
static constexpr uInt16 ADDRESS_MASK = 0x1fff; // either 0x1fff or 0xffff (not needed then)
public:
// breakpoint flags
static const uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command
static const uInt8 ANY_BANK = 255; // breakpoint valid in any bank
static constexpr uInt32 ONE_SHOT = 1 << 0; // used for 'trace' command
static constexpr uInt8 ANY_BANK = 255; // breakpoint valid in any bank
struct Breakpoint
{

View File

@ -48,7 +48,7 @@ using std::right;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
: DebuggerSystem(dbg, console),
myOSystem(osystem)
myOSystem{osystem}
{
// Add case sensitive compare for user labels
// TODO - should user labels be case insensitive too?
@ -1041,7 +1041,7 @@ string CartDebug::saveConfigFile()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveDisassembly()
string CartDebug::saveDisassembly(string path)
{
string NTSC_COLOR[16] = {
"BLACK", "YELLOW", "BROWN", "ORANGE",
@ -1350,9 +1350,16 @@ string CartDebug::saveDisassembly()
// And finally, output the disassembly
out << buf.str();
const string& propsname =
myConsole.properties().get(PropType::Cart_Name) + ".asm";
FilesystemNode node(myOSystem.defaultSaveDir().getPath() + propsname);
if(path.empty())
path = myOSystem.defaultSaveDir().getPath()
+ myConsole.properties().get(PropType::Cart_Name) + ".asm";
else
// Append default extension when missing
if(path.find_last_of('.') == string::npos)
path += ".asm";
FilesystemNode node(path);
stringstream retVal;
try
{
@ -1370,11 +1377,18 @@ string CartDebug::saveDisassembly()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveRom()
string CartDebug::saveRom(string path)
{
const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".a26";
if(path.empty())
path = myOSystem.defaultSaveDir().getPath()
+ myConsole.properties().get(PropType::Cart_Name) + ".a26";
else
// Append default extension when missing
if(path.find_last_of('.') == string::npos)
path += ".a26";
FilesystemNode node(path);
FilesystemNode node(myOSystem.defaultSaveDir().getPath() + rom);
if(myConsole.cartridge().saveROM(node))
return "saved ROM as " + node.getShortPath();
else
@ -1382,7 +1396,7 @@ string CartDebug::saveRom()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveAccessFile()
string CartDebug::saveAccessFile(string path)
{
stringstream out;
out << myConsole.tia().getAccessCounters();
@ -1391,8 +1405,15 @@ string CartDebug::saveAccessFile()
try
{
const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv";
FilesystemNode node(myOSystem.defaultSaveDir().getPath() + rom);
if(path.empty())
path = myOSystem.defaultSaveDir().getPath()
+ myConsole.properties().get(PropType::Cart_Name) + ".csv";
else
// Append default extension when missing
if(path.find_last_of('.') == string::npos)
path += ".csv";
FilesystemNode node(path);
node.write(out);
return "saved access counters as " + node.getShortPath();
@ -1516,7 +1537,7 @@ CartDebug::AddrType CartDebug::addressType(uInt16 addr) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
void CartDebug::getBankDirectives(ostream& buf, const BankInfo& info) const
{
// Start with the offset for this bank
buf << "ORG " << Base::HEX4 << info.offset << endl;

View File

@ -236,13 +236,13 @@ class CartDebug : public DebuggerSystem
/**
Save disassembly and ROM file
*/
string saveDisassembly();
string saveRom();
string saveDisassembly(string path);
string saveRom(string path);
/**
Save access counters file
*/
string saveAccessFile();
string saveAccessFile(string path);
/**
Show Distella directives (both set by the user and determined by Distella)
@ -324,7 +324,7 @@ class CartDebug : public DebuggerSystem
// Analyze of bank of ROM, generating a list of Distella directives
// based on its disassembly
void getBankDirectives(ostream& buf, BankInfo& info) const;
void getBankDirectives(ostream& buf, const BankInfo& info) const;
// Get access enum type from 'flags', taking precendence into account
Device::AccessType accessTypeAbsolute(Device::AccessFlags flags) const;

View File

@ -27,7 +27,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CpuDebug::CpuDebug(Debugger& dbg, Console& console)
: DebuggerSystem(dbg, console),
my6502(mySystem.m6502())
my6502{mySystem.m6502()}
{
}

View File

@ -62,8 +62,8 @@ Debugger* Debugger::myStaticDebugger = nullptr;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Debugger::Debugger(OSystem& osystem, Console& console)
: DialogContainer(osystem),
myConsole(console),
mySystem(console.system())
myConsole{console},
mySystem{console.system()}
{
// Init parser
myParser = make_unique<DebuggerParser>(*this, osystem.settings());
@ -716,10 +716,8 @@ bool Debugger::addFunction(const string& name, const string& definition,
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Debugger::isBuiltinFunction(const string& name)
{
for(const auto& func: ourBuiltinFunctions)
if(name == func.name)
return true;
return false;
return std::any_of(ourBuiltinFunctions.cbegin(), ourBuiltinFunctions.cend(),
[&](const auto& func) { return name == func.name; });
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -76,9 +76,6 @@ class Debugger : public DialogContainer
Debugger(OSystem& osystem, Console& console);
~Debugger() override;
private:
static const Int8 ANY_BANK = -1;
public:
/**
Initialize the debugger dialog container.
@ -284,8 +281,6 @@ class Debugger : public DialogContainer
*/
Dialog* baseDialog() override { return myDialog; }
static const Int32 NOT_FOUND = -1;
private:
/**
Save state of each debugger subsystem and, by default, mark all
@ -367,6 +362,8 @@ class Debugger : public DialogContainer
static std::array<BuiltinFunction, 18> ourBuiltinFunctions;
static std::array<PseudoRegister, 16> ourPseudoRegisters;
static constexpr Int8 ANY_BANK = -1;
private:
// rewind/unwind n states
uInt16 windStates(uInt16 numStates, bool unwind, string& message);

View File

@ -91,7 +91,7 @@ class ByteDerefOffsetExpression : public Expression
class ConstExpression : public Expression
{
public:
ConstExpression(const int value) : Expression(), myValue(value) { }
ConstExpression(const int value) : Expression(), myValue{value} { }
Int32 evaluate() const override
{ return myValue; }
@ -103,7 +103,7 @@ class ConstExpression : public Expression
class CpuMethodExpression : public Expression
{
public:
CpuMethodExpression(CpuMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
CpuMethodExpression(CpuMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
Int32 evaluate() const override
{ return myMethod(Debugger::debugger().cpuDebug()); }
@ -134,7 +134,7 @@ class EqualsExpression : public Expression
class EquateExpression : public Expression
{
public:
EquateExpression(const string& label) : Expression(), myLabel(label) { }
EquateExpression(const string& label) : Expression(), myLabel{label} { }
Int32 evaluate() const override
{ return Debugger::debugger().cartDebug().getAddress(myLabel); }
@ -146,7 +146,7 @@ class EquateExpression : public Expression
class FunctionExpression : public Expression
{
public:
FunctionExpression(const string& label) : Expression(), myLabel(label) { }
FunctionExpression(const string& label) : Expression(), myLabel{label} { }
Int32 evaluate() const override
{ return Debugger::debugger().getFunction(myLabel).evaluate(); }
@ -285,7 +285,7 @@ class PlusExpression : public Expression
class CartMethodExpression : public Expression
{
public:
CartMethodExpression(CartMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
CartMethodExpression(CartMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
Int32 evaluate() const override
{ return myMethod(Debugger::debugger().cartDebug()); }
@ -315,7 +315,7 @@ class ShiftRightExpression : public Expression
class RiotMethodExpression : public Expression
{
public:
RiotMethodExpression(RiotMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
RiotMethodExpression(RiotMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
Int32 evaluate() const override
{ return myMethod(Debugger::debugger().riotDebug()); }
@ -327,7 +327,7 @@ class RiotMethodExpression : public Expression
class TiaMethodExpression : public Expression
{
public:
TiaMethodExpression(TiaMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
TiaMethodExpression(TiaMethod method) : Expression(), myMethod{std::mem_fn(method)} { }
Int32 evaluate() const override
{ return myMethod(Debugger::debugger().tiaDebug()); }

View File

@ -58,8 +58,8 @@ using std::right;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DebuggerParser::DebuggerParser(Debugger& d, Settings& s)
: debugger(d),
settings(s)
: debugger{d},
settings{s}
{
}
@ -565,6 +565,12 @@ string DebuggerParser::eval()
return buf.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const string& DebuggerParser::cartName() const
{
return debugger.myOSystem.console().properties().get(PropType::Cart_Name);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerParser::listTraps(bool listCond)
{
@ -630,15 +636,11 @@ string DebuggerParser::trapStatus(const Trap& trap)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string DebuggerParser::saveScriptFile(string file)
{
// Append 'script' extension when necessary
if(file.find_last_of('.') == string::npos)
file += ".script";
stringstream out;
Debugger::FunctionDefMap funcs = debugger.getFunctionDefMap();
for(const auto& f: funcs)
if (!debugger.isBuiltinFunction(f.first))
out << "function " << f.first << " {" << f.second << "}" << endl;
for(const auto& [name, cmd]: funcs)
if (!debugger.isBuiltinFunction(name))
out << "function " << name << " {" << cmd << "}" << endl;
for(const auto& w: myWatches)
out << "watch " << w << endl;
@ -675,7 +677,16 @@ string DebuggerParser::saveScriptFile(string file)
out << endl;
}
FilesystemNode node(debugger.myOSystem.defaultSaveDir().getPath() + file);
// Append 'script' extension when necessary
if(file.find_last_of('.') == string::npos)
file += ".script";
// Use default path if no path is provided
if(file.find_first_of(FilesystemNode::PATH_SEPARATOR) == string::npos)
file = debugger.myOSystem.defaultSaveDir().getPath() + file;
FilesystemNode node(file);
try
{
node.write(out);
@ -1527,10 +1538,8 @@ void DebuggerParser::executeListfunctions()
const Debugger::FunctionDefMap& functions = debugger.getFunctionDefMap();
if(functions.size() > 0)
{
for(const auto& iter: functions)
commandResult << iter.first << " -> " << iter.second << endl;
}
for(const auto& [name, cmd]: functions)
commandResult << name << " -> " << cmd << endl;
else
commandResult << "no user-defined functions";
}
@ -1837,7 +1846,11 @@ void DebuggerParser::executeS()
void DebuggerParser::executeSave()
{
if(argCount && argStrings[0] == "?")
debugger.myDialog->showBrowser(DebuggerDialog::svScript);
{
debugger.myDialog->showBrowser(DebuggerDialog::svScript, cartName() + ".script");
// avoid printing a new prompt
commandResult << "_EXIT_DEBUGGER";
}
else
commandResult << saveScriptFile(argStrings[0]);
}
@ -1847,9 +1860,13 @@ void DebuggerParser::executeSave()
void DebuggerParser::executeSaveAccess()
{
if(argCount && argStrings[0] == "?")
debugger.myDialog->showBrowser(DebuggerDialog::svAccess);
{
debugger.myDialog->showBrowser(DebuggerDialog::svAccess, cartName() + ".csv");
// avoid printing a new prompt
commandResult << "_EXIT_DEBUGGER";
}
else
commandResult << debugger.cartDebug().saveAccessFile();
commandResult << debugger.cartDebug().saveAccessFile(argCount ? argStrings[0] : EmptyString);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1863,14 +1880,28 @@ void DebuggerParser::executeSaveconfig()
// "savedis"
void DebuggerParser::executeSavedisassembly()
{
commandResult << debugger.cartDebug().saveDisassembly();
if(argCount && argStrings[0] == "?")
{
debugger.myDialog->showBrowser(DebuggerDialog::svDis, cartName() + ".asm");
// avoid printing a new prompt
commandResult << "_EXIT_DEBUGGER";
}
else
commandResult << debugger.cartDebug().saveDisassembly(argCount ? argStrings[0] : EmptyString);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "saverom"
void DebuggerParser::executeSaverom()
{
commandResult << debugger.cartDebug().saveRom();
if(argCount && argStrings[0] == "?")
{
debugger.myDialog->showBrowser(DebuggerDialog::svRom, cartName() + ".a26");
// avoid printing a new prompt
commandResult << "_EXIT_DEBUGGER";
}
else
commandResult << debugger.cartDebug().saveRom(argCount ? argStrings[0] : EmptyString);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1880,12 +1911,22 @@ void DebuggerParser::executeSaveses()
ostringstream filename;
auto timeinfo = BSPF::localTime();
filename << debugger.myOSystem.defaultSaveDir()
<< std::put_time(&timeinfo, "session_%F_%H-%M-%S.txt");
FilesystemNode file(filename.str());
if(debugger.prompt().saveBuffer(file))
commandResult << "saved " + file.getShortPath() + " OK";
<< std::put_time(&timeinfo, "session_%F_%H-%M-%S.txt");
if(argCount && argStrings[0] == "?")
{
debugger.myDialog->showBrowser(DebuggerDialog::svSession, filename.str());
commandResult << "_EXIT_DEBUGGER";
}
else
commandResult << "unable to save session";
{
FilesystemNode file(filename.str());
if(debugger.prompt().saveBuffer(file))
commandResult << "saved " + file.getShortPath() + " OK";
else
commandResult << "unable to save session";
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -3051,7 +3092,7 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
{
"save",
"Save breaks, watches, traps and functions to file xx",
"Example: save commands.script",
"Example: save commands.script, save ?",
true,
false,
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
@ -3061,10 +3102,11 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
{
"saveaccess",
"Save the access counters to CSV file",
"Example: saveaccess (no parameters)",
"Example: saveaccess, saveaccess ?\n"
"NOTE: saves to default save location without ? parameter",
false,
false,
{ Parameters::ARG_END_ARGS },
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
std::mem_fn(&DebuggerParser::executeSaveAccess)
},
@ -3080,34 +3122,34 @@ std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
{
"savedis",
"Save Distella disassembly (with default name)",
"Example: savedis\n"
"NOTE: saves to default save location",
"Save Distella disassembly",
"Example: savedis, savedis ?\n"
"NOTE: saves to default save location without ? parameter",
false,
false,
{ Parameters::ARG_END_ARGS },
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
std::mem_fn(&DebuggerParser::executeSavedisassembly)
},
{
"saverom",
"Save (possibly patched) ROM (with default name)",
"Example: saverom\n"
"NOTE: saves to default save location",
"Save (possibly patched) ROM",
"Example: saverom, saverom ?\n"
"NOTE: saves to default save location without ? parameter",
false,
false,
{ Parameters::ARG_END_ARGS },
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
std::mem_fn(&DebuggerParser::executeSaverom)
},
{
"saveses",
"Save console session (with default name)",
"Example: saveses\n"
"NOTE: saves to default save location",
"Save console session",
"Example: saveses, saveses ?\n"
"NOTE: saves to default save location without ? parameter",
false,
false,
{ Parameters::ARG_END_ARGS },
{ Parameters::ARG_FILE, Parameters::ARG_END_ARGS },
std::mem_fn(&DebuggerParser::executeSaveses)
},

View File

@ -65,6 +65,7 @@ class DebuggerParser
bool validateArgs(int cmd);
string eval();
string saveScriptFile(string file);
const string& cartName() const;
private:
// Constants for argument processing

View File

@ -27,12 +27,12 @@ DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list,
CartDebug::AddrTypeArray& labels,
CartDebug::AddrTypeArray& directives,
CartDebug::ReservedEquates& reserved)
: myDbg(dbg),
myList(list),
mySettings(s),
myReserved(reserved),
myLabels(labels),
myDirectives(directives)
: myDbg{dbg},
myList{list},
mySettings{s},
myReserved{reserved},
myLabels{labels},
myDirectives{directives}
{
bool resolve_code = mySettings.resolveCode;
CartDebug::AddressList& debuggerAddresses = info.addressList;

View File

@ -32,7 +32,7 @@ class Expression
{
public:
Expression(Expression* lhs = nullptr, Expression* rhs = nullptr)
: myLHS(lhs), myRHS(rhs) { }
: myLHS{lhs}, myRHS{rhs} { }
virtual ~Expression() = default;
virtual Int32 evaluate() const { return 0; }

View File

@ -26,7 +26,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TIADebug::TIADebug(Debugger& dbg, Console& console)
: DebuggerSystem(dbg, console),
myTIA(console.tia())
myTIA{console.tia()}
{
}

View File

@ -25,7 +25,7 @@ Cartridge3EPlusWidget::Cartridge3EPlusWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, Cartridge3EPlus& cart)
: CartridgeEnhancedWidget(boss, lfont, nfont, x, y, w, h, cart),
myCart3EP(cart)
myCart3EP{cart}
{
initialize();
}

View File

@ -24,7 +24,7 @@ Cartridge4A50Widget::Cartridge4A50Widget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, Cartridge4A50& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
string info =
"4A50 cartridge - 128K ROM and 32K RAM, split in various bank configurations\n"

View File

@ -27,7 +27,7 @@ CartridgeARWidget::CartridgeARWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeAR& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
size_t size = myCart.mySize;

View File

@ -25,7 +25,7 @@ CartridgeBUSWidget::CartridgeBUSWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeBUS& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
uInt16 size = 8 * 4096;
@ -75,7 +75,6 @@ CartridgeBUSWidget::CartridgeBUSWidget(
ypos += myLineHeight + 4;
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
myFontHeight, "Datastream Pointers", TextAlign::Left);
xpos += lwidth;
myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X, ypos+myLineHeight-2, 4, 4, 6, 32, Common::Base::Fmt::_16_3_2);
myDatastreamPointers->setTarget(this);

View File

@ -24,7 +24,7 @@ CartridgeCDFWidget::CartridgeCDFWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeCDF& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
const int VBORDER = 8;
const int HBORDER = 2;

View File

@ -31,7 +31,7 @@ CartridgeCMWidget::CartridgeCMWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeCM& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
uInt16 size = 4 * 4096;

View File

@ -27,7 +27,7 @@ CartridgeCTYWidget::CartridgeCTYWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeCTY& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
uInt16 size = 8 * 4096;

View File

@ -25,7 +25,7 @@ CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeDPCPlus& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
size_t size = cart.mySize;

View File

@ -25,7 +25,7 @@ CartridgeDPCWidget::CartridgeDPCWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h, CartridgeDPC& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
const int V_GAP = 4;
size_t size = cart.mySize;
@ -68,11 +68,10 @@ CartridgeDPCWidget::CartridgeDPCWidget(
ypos += myLineHeight + V_GAP * 3;
// Data fetchers
int lwidth = _font.getStringWidth("Data fetchers ");
new StaticTextWidget(boss, _font, xpos, ypos, "Data fetchers ");
// Top registers
lwidth = _font.getStringWidth("Counter registers ");
int lwidth = _font.getStringWidth("Counter registers ");
xpos = 2 + _font.getMaxCharWidth() * 2; ypos += myLineHeight + 4;
new StaticTextWidget(boss, _font, xpos, ypos, "Top registers ");
xpos += lwidth;

View File

@ -29,11 +29,11 @@ CartDebugWidget::CartDebugWidget(GuiObject* boss, const GUI::Font& lfont,
int x, int y, int w, int h)
: Widget(boss, lfont, x, y, w, h),
CommandSender(boss),
_nfont(nfont),
myFontWidth(lfont.getMaxCharWidth()),
myFontHeight(lfont.getFontHeight()),
myLineHeight(lfont.getLineHeight()),
myButtonHeight(myLineHeight + 4)
_nfont{nfont},
myFontWidth{lfont.getMaxCharWidth()},
myFontHeight{lfont.getFontHeight()},
myLineHeight{lfont.getLineHeight()},
myButtonHeight{myLineHeight + 4}
{
}

View File

@ -21,9 +21,9 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE78KWidget::CartridgeE78KWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h,
CartridgeMNetwork& cart)
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
int x, int y, int w, int h,
CartridgeMNetwork& cart)
: CartridgeMNetworkWidget(boss, lfont, nfont, x, y, w, h, cart)
{
ostringstream info;

View File

@ -28,7 +28,7 @@ CartridgeEnhancedWidget::CartridgeEnhancedWidget(GuiObject* boss, const GUI::Fon
int x, int y, int w, int h,
CartridgeEnhanced& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
myCart(cart)
myCart{cart}
{
}

Some files were not shown because too many files have changed in this diff Show More