Merge branch 'master' into feature/precise-audio

This commit is contained in:
Christian Speckner 2018-02-04 23:50:16 +01:00
commit 7d7ebb8d03
44 changed files with 450 additions and 362 deletions

View File

@ -9,7 +9,7 @@
SSSS ttt eeeee llll llll aaaaa
===========================================================================
Release 5.0.2 for Linux, MacOSX and Windows
Release 5.1 for Linux, MacOSX and Windows
===========================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
@ -21,30 +21,30 @@ all of your favourite Atari 2600 games again! Stella was originally
developed for Linux by Bradford W. Mott, however, it has been ported to a
number of other platforms and is currently maintained by Stephen Anthony.
This is the 5.0.2 release of Stella for Linux, Mac OSX and Windows. The
This is the 5.1 release of Stella for Linux, Mac OSX and Windows. The
distributions currently available are:
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
Stella-5.0.2-win32.exe (32-bit EXE installer)
Stella-5.0.2-x64.exe (64-bit EXE installer)
Stella-5.0.2-windows.zip (32/64 bit versions)
Stella-5.1-win32.exe (32-bit EXE installer)
Stella-5.1-x64.exe (64-bit EXE installer)
Stella-5.1-windows.zip (32/64 bit versions)
(*) Note: Support for Windows XP is problematic on some systems,
and will probably be discontinued in a future release.
* Binary distribution for MacOS X 10.7 and above :
Stella-5.0.2-macosx.dmg (64-bit Intel)
Stella-5.1-macosx.dmg (64-bit Intel)
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
stella_5.0.2-1_i386.deb
stella_5.0.2-1_amd64.deb
stella_5.1-1_i386.deb
stella_5.1-1_amd64.deb
* Binary distribution in 32-bit & 64-bit RPM format :
stella-5.0.2-2.i386.rpm
stella-5.0.2-2.x86_64.rpm
stella-5.1-2.i386.rpm
stella-5.1-2.x86_64.rpm
* Source code distribution for all platforms :
stella-5.0.2-src.tar.xz
stella-5.1-src.tar.xz
Distribution Site

View File

@ -1,18 +1,8 @@
5.0.2 to 5.1: (January xx, 2018)
5.0.2 to 5.1: (February 4, 2018)
* Thumbulator support is not conditional any more.
* Don't trap write accesses to the datastream pointers in CDF and BUS.
This fixes -dev.thumb.trapfatal 1.
* Complete rework of TV mode and ystart autodetection. The new
implementation is more robust and reduces startup time.
* Add two "grace lines" of black to the top of the frame when
autodetecting ystart.
* Support UNIX style builds (configure / make) on OSX with both
XCode / clang and g++.
* Added "Time Machine" mode, which automatically creates save states
in user-defined intervals. The user can navigate back and forth within
these states inside the emulator and the debugger.
* Huge improvements to the disassembly view in the debugger and
disassembly files created:
@ -23,9 +13,30 @@
- improved cycle count (page penalties, sums created in disassembly)
- improved handling of instruction masking opcodes (e.g. BIT)
* Added "Time Machine" mode, which automatically creates save states
in user-defined intervals. The user can navigate back and forth within
these states inside the emulator and the debugger.
* Fixed change tracking bug during rewind; changes were accumulated
instead of being displayed only for the last rewind step.
* Extended 'rewind' to take a second parameter which allows rewinding
multiple states.
* Added 'unwind' command, which undoes the latest rewind(s)
* Added '<' (unwind) button to debugger.
* Thumbulator support is not conditional any more.
* Moved various developer related settings in new Developer Settings
dialog. These settings now come in two groups (player/developer) and
allow switching all settings at once.
* Don't trap write accesses to the datastream pointers in CDF and BUS.
This fixes -dev.thumb.trapfatal 1.
* Complete rework of TV mode and ystart autodetection. The new
implementation is more robust and reduces startup time.
* Add two "grace lines" of black to the top of the frame when
autodetecting ystart.
* Fixed Genesis controller autodetect (Stay Frosty 2, Scramble, etc).
@ -48,9 +59,6 @@
information). In the case of 'saveses', the filename is now named
based on the date and time of when the command was entered.
* Fixed change tracking bug during rewind; changes were accumulated
instead of being displayed only for the last rewind step.
* Fixed bug with saving snapshots in 1x mode; there was graphical
corruption in some cases. Such snapshots also now include any TV
effects / phosphor blending currently in use.
@ -72,22 +80,16 @@
all ROMs or only the current one. Also added a message (configurable)
when the flash memory is accessed.
* Moved various developer related settings in new Developer Settings
dialog. These settings now come in two groups (player/developer) and
allow switching all settings at once.
* Access to the AtariVox/SaveKey can be signaled with a message.
* Added new interface palette 'Light'
* Added new interface palette 'Light'.
* Improved tab auto-complete in debugger
* Frame stats display made transparent. Also it now displays the real
frame rate and if the developer settings group is enabled.
* Added conditional traps and savestate creation to debugger
* Improved tab auto-complete in debugger.
* Extended 'rewind' to take a second parameter which allows rewinding
multiple states.
* Added 'unwind' command, which undoes the latest rewind(s)
* Added '<' (unwind) button to debugger.
* Added conditional traps and savestate creation to debugger.
* Added 'Options...' button to debugger which gives access to the options
menu during debugging.
@ -107,7 +109,7 @@
* Improved change tracking; more values are tracked and change tracking
now works in case of a break too.
* Added widgets for trackball and SaveKey/AtariVox controllers
* Added widgets for trackball and SaveKey/AtariVox controllers.
* Improved emulation of 'FE' bankswitch scheme (no user-visible changes,
but internally the emulation is much more accurate compared to the
@ -122,6 +124,9 @@
* Added ROM properties for 'Zippy the Porcupine' ROMs, and updated
info for all "Chris Spry (Sprybug)" ROMs.
* Support UNIX style builds (configure / make) on OSX with both
XCode / clang and g++.
* Fixed error when building with uClibc-ng for ARM (thanks to Sergio
Prado).

32
configure vendored
View File

@ -348,22 +348,26 @@ esac
# Determine the C++ compiler
#
echo_n "Looking for C++ compiler... "
if test -n "$_host"; then
compilers="$CXX $_host_prefix-g++ $_host_prefix-c++ $_host_cpu-$_host_os-g++ $_host_cpu-$_host_os-c++"
if test -n "$CXX"; then
echo $CXX
else
compilers="$CXX g++ c++"
fi
for compiler in $compilers; do
if test_compiler "$compiler -std=c++14"; then
CXX=$compiler
echo $CXX
break
if test -n "$_host"; then
compilers="$_host_prefix-g++ $_host_prefix-c++ $_host_cpu-$_host_os-g++ $_host_cpu-$_host_os-c++"
else
compilers="g++ c++"
fi
for compiler in $compilers; do
if test_compiler "$compiler -std=c++14"; then
CXX=$compiler
echo $CXX
break
fi
done
if test -z "$CXX"; then
echo "none found!"
exit 1
fi
done
if test -z $CXX; then
echo "none found!"
exit 1
fi
#

7
debian/changelog vendored
View File

@ -1,3 +1,10 @@
stella (5.1-1) stable; urgency=high
* Version 5.1 release
-- Stephen Anthony <stephena@users.sf.net> Sun, 4 Feb 2018 17:09:59 -0230
stella (5.0.2-1) stable; urgency=high
* Version 5.0.2 release

View File

@ -348,27 +348,27 @@ size can be configured e.g. in the
<td>Frame+1</td>
</tr>
<tr>
<td>Control-r</td>
<td>Alt-Left arrow</td>
<td>Rewind 1</td>
</tr>
<tr>
<td>Control-Shift-r</td>
<td>Shift-Alt-Left arrow</td>
<td>Rewind 10</td>
</tr>
<tr>
<td>Control-Alt-r</td>
<td>Alt-Down arrow</td>
<td>Rewind all</td>
</tr>
<tr>
<td>Control-y</td>
<td>Alt-Right arrow</td>
<td>Unwind 1</td>
</tr>
<tr>
<td>Control-Shift-y</td>
<td>Shift-Alt-Right arrow</td>
<td>Unwind 10</td>
</tr>
<tr>
<td>Control-Alt-y</td>
<td>Alt-Up arrow</td>
<td>Unwind all</td>
</tr>
<tr>
@ -377,6 +377,7 @@ size can be configured e.g. in the
</tr>
</table>
</p>
For MacOS use 'Cmd' instead of &nbsp;'Alt' key.
<p>To the left of the global buttons, you find the "Options..." button.</p>
<ul>
<p><img src="graphics/debugger_options.png"></p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -61,7 +61,7 @@
<br><br><br>
<center><b>February 1999 - January 2018</b></center>
<center><b>February 1999 - February 2018</b></center>
<center><b>The Stella Team</b></center>
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
@ -1622,32 +1622,38 @@
</tr>
<tr>
<td>Rewind by one state (pauses emulation)</td>
<td>Enter/Exit the <a href="#TimeMachine"><b>Time Machine</b></a> dialog</td>
<td>t to enter, t/Escape/Space to exit</td>
<td>t to enter, t/Escape/Space to exit</td>
</tr>
<tr>
<td>Rewind by one state (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Left arrow</td>
<td>Cmd + Left arrow</td>
</tr>
<tr>
<td>Rewind by 10 states (pauses emulation)</td>
<td>Rewind by 10 states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Shift-Alt + Left arrow</td>
<td>Shift-Cmd + Left arrow</td>
</tr>
<tr>
<td>Rewind all states (pauses emulation)</td>
<td>Rewind all states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Down arrow</td>
<td>Cmd + Down arrow</td>
</tr>
<tr>
<td>Unwind by one state (pauses emulation)</td>
<td>Unwind by one state (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Right arrow</td>
<td>Cmd + Right arrow</td>
</tr>
<tr>
<td>Unwind by 10 states (pauses emulation)</td>
<td>Unwind by 10 states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Shift-Alt + Right arrow</td>
<td>Shift-Cmd + Right arrow</td>
</tr>
<tr>
<td>Unwind all states (pauses emulation)</td>
<td>Unwind all states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Up arrow</td>
<td>Cmd + Up arrow</td>
</tr>
@ -1794,36 +1800,49 @@
<a name="TimeMachine">Stella's 'Time Machine'</a></h2>
<p>A special feature of Stella is the 'Time Machine' mode. In this mode, Stella
automatically creates savestates in regular, user-defined intervals. You can then
interrupt the current emulation and navigate back and forth within the timeline.
automatically creates savestates in regular, user-defined intervals. At any time,
the user can interrupt the current emulation and navigate back and forth
within the saved timeline.
This can be done either by using the Time Machine hotkeys described in
<a href="#Hotkeys"><b>Hotkeys</b> - Other Keys</a> or by using the Time Machine
dialog. To enter this dialog, either use one of the hotkeys or press 'T'.</p>
dialog. This dialog is automatically entered when using one of the Time Machine
hotkeys. The hotkeys continue to function within the dialog.</p>
<p><b>Time Machine</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none">
<tr>
<td>TODO: Screenshot</td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top">
<table border="1" cellpadding="4">
<tr><th>Item</th><th>Description</th></tr>
<tr><td>Button</td><td>TODO</td></tr>
<tr><td>Button</td><td></td></tr>
<tr><td>Button</td><td></td></tr>
<tr><td>Button</td><td></td></tr>
<tr><td>Button</td><td></td></tr>
<tr><td>Button</td><td></td></tr>
<tr><td>Button</td><td></td></tr>
</table>
</td>
</tr>
</table>
<td><img src="graphics/timemachine.png"></td>
<p>The dialog items are explained in the following two tables.</p>
<p><b>Top row (left to right)</b></p>
<table border="1" cellpadding="4">
<tr><th>Item</th><th>Description</th></tr>
<tr><td>Current state</td><td>Shows the currently loaded state's number</td></tr>
<tr><td>'Timeline' slider</td><td>Shows the position of the current state in the
recorded timeline. A state can be selected by dragging the slider with the mouse.
To visualize state compression, small marks split the timeline into five, equally
sized state number intervals.</td></tr>
<tr><td>Total states</td><td>Shows the total number of save states in the
Time Machine</td></tr>
</table>
<p><b>Bottom row (left to right)</b></p>
<table border="1" cellpadding="4">
<tr><th>Item</th><th>Description</th></tr>
<tr><td>Current time</td><td>Shows the time of the currently selected status,
relative to the first one</td></tr>
<tr><td>'Rewind All' button</td><td>Navigates back to the begin of the timeline</td></tr>
<tr><td>'Rewind One' button</td><td>Navigates back by one state</td></tr>
<tr><td>'Continue' button</td><td>Exits the dialog and continues emulation.</td></tr>
<tr><td>Navigation info</td><td>Informs about the interval of the user's last
Time Machine navigation. The interval can vary if the timeline is compressed.</td></tr>
<tr><td>'Unwind One' button</td><td>Navigates forward by one state</td></tr>
<tr><td>'Unwind All' button</td><td>Navigates forward to the end of the timeline</td></tr>
<tr><td>Total time</td><td>Shows the total time covered by the save states
(aka 'Horizon')</td></tr>
</table>
<br>
<p>The 'Time Machine' mode can be configured by the user. For details see
<a href="#Debugger"><b>Developer Options</b> - Time Machine dialog</a></h2>.</p>
<a href="#Debugger"><b>Developer Options</b> - Time Machine</a></h2> tab.</p>
<!-- ///////////////////////////////////////////////////////////////////////// -->
<br><br>
@ -2538,10 +2557,14 @@
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;thumb.trapfatal &lt;1|0&gt;</pre></td>
<td>The default of true allows the Thumb ARM emulation to
throw an exception and enter the debugger on fatal errors. When disabled, such
fatal errors are simply logged, and emulation continues. Do not use this
unless you know exactly what you're doing, as it changes the behaviour as compared
to real hardware.</td>
throw an exception and enter the debugger on fatal errors. When disabled, such
fatal errors are simply logged, and emulation continues. Do not use this
unless you know exactly what you're doing, as it changes the behaviour as
compared to real hardware.</td>
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;eepromaccess &lt;1|0&gt;</pre></td>
<td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is
signalled by a message.</td>
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;tv.jitter &lt;1|0&gt;</pre></td>
<td>Enable TV jitter/roll effect, when there are too many or too few scanlines
@ -2740,13 +2763,15 @@
</td>
</tr>
</table>
<p><b>Audit ROMs</b> dialog:</p>
<br>
<p><b>Developer Settings</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none">
<tr>
<td><img src="graphics/romaudit.png"></td>
<td><img src="graphics/options_developer.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top"><br>This dialog is described in further detail in
<b>Advanced Configuration - <a href="#ROMAudit">ROM Audit Mode</a></b>.</td>
<td valign="top"><br>This tab is described in further detail in
<b>Advanced Configuration - <a href="#Debugger">Developer Options/Integrated Debugger</a></b>.</td>
</td>
</tr>
</table>
<br>
@ -2760,18 +2785,17 @@
</td>
</tr>
</table>
<br>
<p><b>Developer Settings</b> dialog:</p>
<p><b>Audit ROMs</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none">
<tr>
<td><img src="graphics/options_developer.png"></td>
<td><img src="graphics/romaudit.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top"><br>This tab is described in further detail in
<b>Advanced Configuration - <a href="#Debugger">Developer Options/Integrated Debugger</a></b>.</td>
</td>
<td valign="top"><br>This dialog is described in further detail in
<b>Advanced Configuration - <a href="#ROMAudit">ROM Audit Mode</a></b>.</td>
</tr>
</table>
<br>
</blockquote>
<h2><b><a name="Remapping">Event Remapping/Input Devices</a></b></h2>
@ -3115,6 +3139,7 @@
<td>Thumb ARM emulation throws an exception and enters the debugger on fatal errors</td>
<td><span style="white-space:nowrap">-plr.thumb.trapfatal<br/>-dev.thumb.trapfatal</span></td>
</tr>
<tr><td>Display AtariVox...</td><td>Display a message when the AtariVox/SaveKey EEPROM is read or written</td><td>-plr.eepromaccess<br/>-dev.eepromaccess</td></tr>
</table>
</td>
</tr>

View File

@ -78,6 +78,9 @@ class LinkedObjectPool
SLOW, but only required for messages
*/
uInt32 currentIdx() const {
if(empty())
return 0;
iter it = myCurrent;
uInt32 idx = 1;

View File

@ -284,7 +284,6 @@ string RewindManager::getUnitString(Int64 cycles)
const Int32 PAL_FREQ = 1182298; // ~76*312*50
const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second
// TODO: do we need hours here? don't think so
const Int32 NUM_UNITS = 5;
const string UNIT_NAMES[NUM_UNITS] = { "cycle", "scanline", "frame", "second", "minute" };
const Int64 UNIT_CYCLES[NUM_UNITS + 1] = { 1, 76, 76 * scanlines, freq, freq * 60, Int64(1) << 62 };
@ -298,7 +297,7 @@ string RewindManager::getUnitString(Int64 cycles)
{
// use the lower unit up to twice the nextCycles unit, except for an exact match of the nextCycles unit
// TODO: does the latter make sense, e.g. for ROMs with changing scanlines?
if(cycles == 0 || cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0)
if(cycles == 0 || (cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0))
break;
}
result << cycles / UNIT_CYCLES[i] << " " << UNIT_NAMES[i];
@ -309,14 +308,13 @@ string RewindManager::getUnitString(Int64 cycles)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::getFirstCycles() const
uInt64 RewindManager::getFirstCycles() const
{
// TODO: check if valid
return Common::LinkedObjectPool<RewindState>::const_iter(myStateList.first())->cycles;
return !myStateList.empty() ? myStateList.first()->cycles : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::getCurrentCycles() const
uInt64 RewindManager::getCurrentCycles() const
{
if(myStateList.currentIsValid())
return myStateList.current().cycles;
@ -325,10 +323,9 @@ uInt32 RewindManager::getCurrentCycles() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::getLastCycles() const
uInt64 RewindManager::getLastCycles() const
{
// TODO: check if valid
return Common::LinkedObjectPool<RewindState>::const_iter(myStateList.last())->cycles;
return !myStateList.empty() ? myStateList.last()->cycles : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -149,9 +149,9 @@ class RewindManager
uInt32 getCurrentIdx() { return myStateList.currentIdx(); }
uInt32 getLastIdx() { return myStateList.size(); }
uInt32 getFirstCycles() const;
uInt32 getCurrentCycles() const;
uInt32 getLastCycles() const;
uInt64 getFirstCycles() const;
uInt64 getCurrentCycles() const;
uInt64 getLastCycles() const;
/**
Get a collection of cycle timestamps, offset from the first one in

View File

@ -49,6 +49,15 @@ class FixedStack
T pop() { return std::move(_stack[--_size]); }
uInt32 size() const { return _size; }
void replace(const T& oldItem, const T& newItem) {
for(uInt32 i = 0; i < _size; ++i) {
if(_stack[i] == oldItem) {
_stack[i] = newItem;
return;
}
}
}
// Apply the given function to every item in the stack
// We do it this way so the stack API can be preserved,
// and no access to individual elements is allowed outside

View File

@ -27,7 +27,7 @@
#include "StateManager.hxx"
#define STATE_HEADER "05009901state"
#define STATE_HEADER "05010000state"
// #define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "5.1_b1"
#define STELLA_BUILD "3826"
#define STELLA_VERSION "5.1"
#define STELLA_BUILD "4138"
#endif

View File

@ -76,6 +76,7 @@ using std::memcpy;
// Common array types
using IntArray = std::vector<Int32>;
using uIntArray = std::vector<uInt32>;
using BoolArray = std::vector<bool>;
using ByteArray = std::vector<uInt8>;
using ShortArray = std::vector<uInt16>;

View File

@ -301,31 +301,21 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, false);
break;
return;
case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true);
break;
return;
case KBDK_DOWN: // Alt-down rewinds to start of list
enterTimeMachineMenuMode(1000, false);
break;
return;
case KBDK_UP: // Alt-up rewinds to end of list
enterTimeMachineMenuMode(1000, true);
break;
return;
default:
handled = false;
break;
}
}
// These only work when in emulation mode
if(!handled && (myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE))
{
handled = true;
switch(key)
{
// These can work in pause mode too
case KBDK_EQUALS:
myOSystem.frameBuffer().changeWindowedVidMode(+1);
break;
@ -390,10 +380,10 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
if(mod & KBDM_SHIFT)
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable());
myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable());
else
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable());
myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable());
}
break;
@ -402,10 +392,10 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
if(mod & KBDM_SHIFT)
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable());
myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable());
else
myOSystem.frameBuffer().showMessage(
myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable());
myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable());
}
break;
@ -420,7 +410,7 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
if(mod & KBDM_SHIFT)
myOSystem.console().toggleP1Collision();
else
myOSystem.console().toggleP1Bit();
myOSystem.console().toggleP1Bit();
break;
case KBDK_C:
@ -508,8 +498,8 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{
ostringstream buf;
buf << "Disabling snapshots, generated "
<< (myContSnapshotCounter / myContSnapshotInterval)
<< " files";
<< (myContSnapshotCounter / myContSnapshotInterval)
<< " files";
myOSystem.frameBuffer().showMessage(buf.str());
setContinuousSnapshots(0);
}
@ -2161,6 +2151,11 @@ void EventHandler::enterTimeMachineMenuMode(uInt32 numWinds, bool unwind)
// add one extra state if we are in Time Machine mode
// TODO: maybe remove this state if we leave the menu at this new state
myOSystem.state().addExtraState("enter Time Machine dialog"); // force new state
if(numWinds)
myOSystem.state().windStates(numWinds, unwind);
if(numWinds)
myOSystem.state().windStates(numWinds, unwind);
// TODO: display last wind message (numWinds != 0) in time machine dialog
enterMenuMode(EventHandlerState::TIMEMACHINE);
@ -2204,6 +2199,7 @@ void EventHandler::setEventState(EventHandlerState state)
break;
case EventHandlerState::TIMEMACHINE:
myOSystem.timeMachine().requestResize();
myOverlay = &myOSystem.timeMachine();
enableTextEvents(true);
break;

View File

@ -147,7 +147,6 @@ bool FrameBuffer::initialize()
FBSurface::setPalette(myPalette);
myGrabMouse = myOSystem.settings().getBool("grabmouse");
myZoomMode = myOSystem.settings().getInt("tia.zoom");
// Create a TIA surface; we need it for rendering TIA images
myTIASurface = make_unique<TIASurface>(myOSystem);
@ -235,7 +234,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title,
{
myStatsMsg.surface = allocateSurface(myStatsMsg.w, myStatsMsg.h);
myStatsMsg.surface->attributes().blending = true;
//myStatsMsg.surface->attributes().blendalpha = 80;
myStatsMsg.surface->attributes().blendalpha = 92; //aligned with TimeMachineDialog
myStatsMsg.surface->applyAttributes();
}
@ -387,9 +386,10 @@ void FrameBuffer::drawFrameStats()
myStatsMsg.surface->invalidate();
string bsinfo = info.BankSwitch +
(myOSystem.settings().getBool("dev.settings") ? "| Developer" : "| Player");
(myOSystem.settings().getBool("dev.settings") ? "| Developer" : "");
// draw shadowed text
color = myOSystem.console().tia().scanlinesLastFrame() != myLastScanlines ? kDbgColorRed : myStatsMsg.color;
color = myOSystem.console().tia().scanlinesLastFrame() != myLastScanlines ?
uInt32(kDbgColorRed) : myStatsMsg.color;
std::snprintf(msg, 30, "%3u", myOSystem.console().tia().scanlinesLastFrame());
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor);
@ -404,13 +404,13 @@ void FrameBuffer::drawFrameStats()
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
// draw bankswitching type
myStatsMsg.surface->drawString(font(), bsinfo, XPOS, YPOS + font().getFontHeight(),
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
myStatsMsg.surface->setDirty();
myStatsMsg.surface->setDstPos(myImageRect.x() + 1, myImageRect.y() + 1);
myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8);
myStatsMsg.surface->render();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -631,7 +631,7 @@ bool FrameBuffer::changeWindowedVidMode(int direction)
resetSurfaces();
showMessage(mode.description);
myZoomMode = mode.zoom;
myOSystem.settings().setValue("tia.zoom", mode.zoom);
return true;
}
#endif
@ -789,17 +789,11 @@ const VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen)
if(state == EventHandlerState::DEBUGGER || state == EventHandlerState::LAUNCHER)
myCurrentModeList->setZoom(1);
else
myCurrentModeList->setZoom(myZoomMode);
myCurrentModeList->setZoom(myOSystem.settings().getInt("tia.zoom"));
return myCurrentModeList->current();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::setZoomMode(uInt32 mode)
{
myZoomMode = mode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// VideoMode implementation
@ -984,11 +978,11 @@ void FrameBuffer::VideoModeList::setZoom(uInt32 zoom)
kScrollColor Normal scrollbar color
kScrollColorHi Highlighted scrollbar color
*** Slider colors ***
kSliderColor,
kSliderColorHi
kSliderBGColor
kSliderBGColorHi
kSliderBGColorLo,
kSliderColor Enabled slider
kSliderColorHi Focussed slider
kSliderBGColor Enabled slider background
kSliderBGColorHi Focussed slider background
kSliderBGColorLo Disabled slider background
*** Debugger colors ***
kDbgChangedColor Background color for changed cells
kDbgChangedTextColor Text color for changed cells
@ -1031,7 +1025,7 @@ uInt32 FrameBuffer::ourGUIColors[3][kNumColors-256] = {
0xe1e1e1, 0xe5f1fb, 0x808080, 0x0078d7, 0x000000, 0x000000, // buttons
0x333333, // checkbox
0xc0c0c0, 0x808080, // scrollbar
0x333333, 0x0078d7, 0xc0c0c0, 0x808080, 0xe1e1e1, // slider
0x333333, 0x0078d7, 0xc0c0c0, 0xffffff, 0xc0c0c0, // slider 0xBDDEF9| 0xe1e1e1 | 0xffffff
0xffc0c0, 0x000000, 0xe00000, 0xc00000, // debugger
0xffffff, 0x333333, 0xf0f0f0, 0x808080, 0xc0c0c0 // other
}

View File

@ -193,11 +193,6 @@ class FrameBuffer
*/
const VariantList& supportedTIAZoomLevels() const { return myTIAZoomLevels; }
/*
Set the current zoom mode.
*/
void setZoomMode(uInt32 mode);
/**
Get the font object(s) of the framebuffer
*/
@ -528,9 +523,6 @@ class FrameBuffer
// Names of the TIA zoom levels that can be used for this framebuffer
VariantList myTIAZoomLevels;
// curently selected zoom mode
uInt32 myZoomMode;
// Holds a reference to all the surfaces that have been created
vector<shared_ptr<FBSurface>> mySurfaceList;

View File

@ -1231,6 +1231,8 @@ void TIA::tickHblank()
if (myExtendedHblank) myHstate = HState::frame;
break;
}
if (myExtendedHblank && myHctr > 67) myPlayfield.tick(myHctr - 68 - myHctrDelta);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1271,6 +1273,7 @@ void TIA::nextLine()
cloneLastLine();
}
myPlayfield.tick(0);
myHctr = 0;
if (!myMovementInProgress && myLinesSinceChange < 2) myLinesSinceChange++;

View File

@ -28,7 +28,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ConfigPathDialog::ConfigPathDialog(
OSystem& osystem, DialogContainer& parent,
const GUI::Font& font, GuiObject* boss)
const GUI::Font& font, GuiObject* boss, int max_w, int max_h)
: Dialog(osystem, parent, font, "Configure paths"),
CommandSender(boss),
myFont(font),
@ -48,7 +48,7 @@ ConfigPathDialog::ConfigPathDialog(
ButtonWidget* b;
// Set real dimensions
_w = 64 * fontWidth + HBORDER*2;
_w = std::min(64 * fontWidth + HBORDER*2, max_w);
_h = 9 * (lineHeight + V_GAP) + VBORDER;
xpos = HBORDER; ypos = VBORDER;

View File

@ -35,7 +35,7 @@ class ConfigPathDialog : public Dialog, public CommandSender
{
public:
ConfigPathDialog(OSystem& osystem, DialogContainer& parent,
const GUI::Font& font, GuiObject* boss);
const GUI::Font& font, GuiObject* boss, int max_w, int max_h);
virtual ~ConfigPathDialog();
private:

View File

@ -205,6 +205,7 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font)
myTVJitterWidget->getRight() + fontWidth * 3, ypos - 1,
"Recovery ", 0, kTVJitterChanged);
myTVJitterRecWidget->setMinValue(1); myTVJitterRecWidget->setMaxValue(20);
myTVJitterRecWidget->setTickmarkInterval(5);
wid.push_back(myTVJitterRecWidget);
myTVJitterRecLabelWidget = new StaticTextWidget(myTab, font,
myTVJitterRecWidget->getRight() + 4,

View File

@ -30,6 +30,8 @@
#include "ContextMenu.hxx"
#include "PopUpWidget.hxx"
#include "Settings.hxx"
#include "Console.hxx"
#include "Vec.hxx"
@ -813,16 +815,20 @@ Widget* Dialog::TabFocus::getNewFocus()
bool Dialog::getResizableBounds(uInt32& w, uInt32& h) const
{
const GUI::Rect& r = instance().frameBuffer().imageRect();
bool ntsc = instance().console().about().InitialFrameRate == "60";
uInt32 aspect = instance().settings().getInt(ntsc ?"tia.aspectn" : "tia.aspectp");
if(r.width() <= FrameBuffer::kFBMinW || r.height() <= FrameBuffer::kFBMinH)
{
w = uInt32(0.8 * FrameBuffer::kTIAMinW) * 2;
w = uInt32(aspect * FrameBuffer::kTIAMinW) * 2 / 100;
h = FrameBuffer::kTIAMinH * 2;
return false;
}
else
{
w = std::max(uInt32(0.8 * r.width()), uInt32(FrameBuffer::kFBMinW));
h = std::max(uInt32(0.8 * r.height()), uInt32(FrameBuffer::kFBMinH));
w = std::max(uInt32(aspect * r.width() / 100), uInt32(FrameBuffer::kFBMinW));
h = std::max(uInt32(aspect * r.height() / 100), uInt32(FrameBuffer::kFBMinH));
return true;
}
}

View File

@ -75,10 +75,11 @@ class Dialog : public GuiObject
/** Returns the base surface associated with this dialog. */
FBSurface& surface() const { return *_surface; }
/** Adds a surface to this dialog, which is rendered on top of the
base surface whenever the base surface is re-rendered. Since
the surface render() call will always occur in such a case, the
surface should call setVisible() to enable/disable its output.
/**
Adds a surface to this dialog, which is rendered on top of the
base surface whenever the base surface is re-rendered. Since
the surface render() call will always occur in such a case, the
surface should call setVisible() to enable/disable its output.
*/
void addSurface(shared_ptr<FBSurface> surface);
@ -89,6 +90,11 @@ class Dialog : public GuiObject
void setTitle(const string& title);
bool hasTitle() { return !_title.empty(); }
/** Determine the maximum bounds based on the given width and height
Returns whether or not a large font can be used within these bounds.
*/
bool getResizableBounds(uInt32& w, uInt32& h) const;
protected:
virtual void draw() override { }
void releaseFocus() override;
@ -123,11 +129,6 @@ class Dialog : public GuiObject
void processCancelWithoutWidget(bool state) { _processCancel = state; }
/** Determine the maximum bounds based on the given width and height
Returns whether or not a large font can be used within these bounds.
*/
bool getResizableBounds(uInt32& w, uInt32& h) const;
void initTitle(const GUI::Font& font, const string& title);
private:

View File

@ -119,7 +119,7 @@ void DialogContainer::addDialog(Dialog* d)
const GUI::Rect& r = myOSystem.frameBuffer().imageRect();
if(uInt32(d->getWidth()) > r.width() || uInt32(d->getHeight()) > r.height())
myOSystem.frameBuffer().showMessage(
"Unable to show dialog box; resize current window");
"Unable to show dialog box; FIX THE CODE");
else
myDialogStack.push(d);
}

View File

@ -134,6 +134,14 @@ class DialogContainer
*/
const Dialog* baseDialog() const { return myBaseDialog; }
/**
Inform the container that it should resize according to the current
screen dimensions. We make this virtual, since the container may or
may not choose to do a resize, and even if it does, *how* it does it
is determined by the specific container.
*/
virtual void requestResize() { }
private:
void reset();

View File

@ -37,6 +37,7 @@
#include "AboutDialog.hxx"
#include "OptionsDialog.hxx"
#include "Launcher.hxx"
#include "Settings.hxx"
#ifdef CHEATCODE_SUPPORT
#include "CheatCodeDialog.hxx"
@ -48,7 +49,8 @@
OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
GuiObject* boss, int max_w, int max_h, stellaMode mode)
: Dialog(osystem, parent),
myMode(mode)
myMode(mode),
_boss(boss)
{
const GUI::Font& font = instance().frameBuffer().font();
initTitle(font, "Options");
@ -97,7 +99,6 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
b = ADD_OD_BUTTON("Developer" + ELLIPSIS, kDevelopCmd);
wid.push_back(b);
// Move to second column
xoffset += buttonWidth + 10; yoffset = VBORDER;
@ -131,8 +132,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
myAudioDialog = make_unique<AudioDialog>(osystem, parent, font);
myInputDialog = make_unique<InputDialog>(osystem, parent, font, max_w, max_h);
myUIDialog = make_unique<UIDialog>(osystem, parent, font);
mySnapshotDialog = make_unique<SnapshotDialog>(osystem, parent, font);
myConfigPathDialog = make_unique<ConfigPathDialog>(osystem, parent, font, boss);
mySnapshotDialog = make_unique<SnapshotDialog>(osystem, parent, font, max_w, max_h);
myConfigPathDialog = make_unique<ConfigPathDialog>(osystem, parent, font, boss, max_w, max_h);
myRomAuditDialog = make_unique<RomAuditDialog>(osystem, parent, font, max_w, max_h);
myGameInfoDialog = make_unique<GameInfoDialog>(osystem, parent, font, this);
#ifdef CHEATCODE_SUPPORT
@ -190,6 +191,15 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd,
switch(cmd)
{
case kVidCmd:
// This dialog is resizable under certain conditions, so we need
// to re-create it as necessary
if(myMode != launcher)
{
uInt32 w = 0, h = 0;
getResizableBounds(w, h);
myVideoDialog = make_unique<VideoDialog>(instance(), parent(), instance().frameBuffer().font(), w, h);
}
myVideoDialog->open();
break;
@ -206,10 +216,29 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd,
break;
case kSnapCmd:
// This dialog is resizable under certain conditions, so we need
// to re-create it as necessary
if(myMode != launcher)
{
uInt32 w = 0, h = 0;
getResizableBounds(w, h);
mySnapshotDialog = make_unique<SnapshotDialog>(instance(), parent(), instance().frameBuffer().font(), w, h);
}
mySnapshotDialog->open();
break;
case kCfgPathsCmd:
// This dialog is resizable under certain conditions, so we need
// to re-create it as necessary
if(myMode != launcher)
{
uInt32 w = 0, h = 0;
getResizableBounds(w, h);
myConfigPathDialog = make_unique<ConfigPathDialog>(instance(), parent(),
instance().frameBuffer().font(), _boss, w, h);
}
myConfigPathDialog->open();
break;

View File

@ -85,6 +85,8 @@ class OptionsDialog : public Dialog
// Indicates if this dialog is used for global (vs. in-game) settings
stellaMode myMode;
GuiObject* _boss;
enum {
kVidCmd = 'VIDO',
kAudCmd = 'AUDO',

View File

@ -26,7 +26,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent,
const GUI::Font& font)
const GUI::Font& font, int max_w, int max_h)
: Dialog(osystem, parent, font, "Snapshot settings"),
myFont(font)
{
@ -43,7 +43,7 @@ SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent,
ButtonWidget* b;
// Set real dimensions
_w = 64 * fontWidth + HBORDER * 2;
_w = std::min(max_w, 64 * fontWidth + HBORDER * 2);
_h = 10 * (lineHeight + 4) + VBORDER + _th;
xpos = HBORDER; ypos = VBORDER + _th;

View File

@ -34,7 +34,7 @@ class SnapshotDialog : public Dialog
{
public:
SnapshotDialog(OSystem& osystem, DialogContainer& parent,
const GUI::Font& font);
const GUI::Font& font, int max_w, int max_h);
virtual ~SnapshotDialog();
private:

View File

@ -25,18 +25,14 @@
#include "TimeLineWidget.hxx"
// TODO - remove all references to _stepValue__
// - fix posToValue to use _stepValue
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h,
const string& label, int labelWidth, int cmd)
const string& label, uInt32 labelWidth, int cmd)
: ButtonWidget(boss, font, x, y, w, h, label, cmd),
_value(0),
_stepValue__(1),
_valueMin(0),
_valueMax(100),
_valueMax(0),
_isDragging(false),
_labelWidth(labelWidth)
{
@ -53,10 +49,9 @@ TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setValue(int value)
void TimeLineWidget::setValue(uInt32 value)
{
if(value < _valueMin) value = _valueMin;
else if(value > _valueMax) value = _valueMax;
value = BSPF::clamp(value, _valueMin, _valueMax);
if(value != _value)
{
@ -67,13 +62,13 @@ void TimeLineWidget::setValue(int value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setMinValue(int value)
void TimeLineWidget::setMinValue(uInt32 value)
{
_valueMin = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setMaxValue(int value)
void TimeLineWidget::setMaxValue(uInt32 value)
{
_valueMax = value;
}
@ -81,27 +76,32 @@ void TimeLineWidget::setMaxValue(int value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setStepValues(const IntArray& steps)
{
// Try to allocate as infrequently as possible
if(steps.size() > _stepValue.capacity())
_stepValue.reserve(2 * steps.size());
_stepValue.clear();
double scale = (_w - _labelWidth - 4) / double(steps.back());
// If no steps are defined, just use the maximum value
if(steps.size() > 0)
{
// Try to allocate as infrequently as possible
if(steps.size() > _stepValue.capacity())
_stepValue.reserve(2 * steps.size());
// Skip the very last value; we take care of it outside the end of the loop
for(uInt32 i = 0; i < steps.size() - 1; ++i)
_stepValue.push_back(int(steps[i] * scale));
double scale = (_w - _labelWidth - 2) / double(steps.back());
// Due to integer <-> double conversion, the last value is sometimes
// slightly less than the maximum value; we assign it manually to fix this
_stepValue.push_back(_w - _labelWidth - 4);
// Skip the very last value; we take care of it outside the end of the loop
for(uInt32 i = 0; i < steps.size() - 1; ++i)
_stepValue.push_back(int(steps[i] * scale));
// Due to integer <-> double conversion, the last value is sometimes
// slightly less than the maximum value; we assign it manually to fix this
_stepValue.push_back(_w - _labelWidth - 2);
}
else
_stepValue.push_back(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::handleMouseMoved(int x, int y)
{
// TODO: when the mouse is dragged outside the widget, the slider should
// snap back to the old value.
if(isEnabled() && _isDragging && x >= int(_labelWidth))
setValue(posToValue(x - _labelWidth));
}
@ -130,47 +130,13 @@ void TimeLineWidget::handleMouseWheel(int x, int y, int direction)
{
if(isEnabled())
{
if(direction < 0)
handleEvent(Event::UIUp);
else if(direction > 0)
handleEvent(Event::UIDown);
if(direction < 0 && _value < _valueMax)
setValue(_value + 1);
else if(direction > 0 && _value > _valueMin)
setValue(_value - 1);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TimeLineWidget::handleEvent(Event::Type e)
{
if(!isEnabled())
return false;
switch(e)
{
case Event::UIDown:
case Event::UILeft:
case Event::UIPgDown:
setValue(_value - _stepValue__);
break;
case Event::UIUp:
case Event::UIRight:
case Event::UIPgUp:
setValue(_value + _stepValue__);
break;
case Event::UIHome:
setValue(_valueMin);
break;
case Event::UIEnd:
setValue(_valueMax);
break;
default:
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::drawWidget(bool hilite)
{
@ -183,13 +149,26 @@ void TimeLineWidget::drawWidget(bool hilite)
isEnabled() ? kTextColor : kColor, TextAlign::Right);
// Draw the box
s.box(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor, kShadowColor);
s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor);
// Fill the box
s.fillRect(_x + _labelWidth + 2, _y + 2, _w - _labelWidth - 4, _h - 4,
s.fillRect(_x + _labelWidth + 1, _y + 1, _w - _labelWidth - 2, _h - 2,
!isEnabled() ? kBGColorHi : kWidColor);
// Draw the 'bar'
s.fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4,
int vp = valueToPos(_value);
s.fillRect(_x + _labelWidth + 1, _y + 1, vp, _h - 2,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);
// add 4 tickmarks for 5 intervals
int numTicks = std::min(5, int(_stepValue.size()));
for(int i = 1; i < numTicks; ++i)
{
int idx = int((_stepValue.size() * i + numTicks / 2) / numTicks);
if(idx > 1)
{
int tp = valueToPos(idx - 1);
s.vLine(_x + _labelWidth + tp, _y + _h / 2, _y + _h - 2, tp > vp ? kSliderColor : kWidColor);
}
}
#else
// Draw the label, if any
if(_labelWidth > 0)
@ -208,25 +187,19 @@ void TimeLineWidget::drawWidget(bool hilite)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TimeLineWidget::valueToPos(int value)
uInt32 TimeLineWidget::valueToPos(uInt32 value)
{
if(value < _valueMin) value = _valueMin;
else if(value > _valueMax) value = _valueMax;
int real = _stepValue[BSPF::clamp(value, _valueMin, _valueMax)];
#if 0
int range = std::max(_valueMax - _valueMin, 1); // don't divide by zero
int actual = ((_w - _labelWidth - 4) * (value - _valueMin) / range);
cerr << "i=" << value << " real=" << real << endl << "actual=" << actual << endl << endl;
#endif
return real;
return _stepValue[BSPF::clamp(value, _valueMin, _valueMax)];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TimeLineWidget::posToValue(int pos)
uInt32 TimeLineWidget::posToValue(uInt32 pos)
{
int value = (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - 4) + _valueMin;
// Find the interval in which 'pos' falls, and then the endpoint which
// it is closest to
for(uInt32 i = 0; i < _stepValue.size() - 1; ++i)
if(pos >= _stepValue[i] && pos <= _stepValue[i+1])
return (_stepValue[i+1] - pos) < (pos - _stepValue[i]) ? i+1 : i;
// Scale the position to the correct interval (according to step value)
return value - (value % _stepValue__);
return _valueMax;
}

View File

@ -25,15 +25,15 @@ class TimeLineWidget : public ButtonWidget
public:
TimeLineWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, const string& label = "",
int labelWidth = 0, int cmd = 0);
uInt32 labelWidth = 0, int cmd = 0);
void setValue(int value);
int getValue() const { return _value; }
void setValue(uInt32 value);
uInt32 getValue() const { return _value; }
void setMinValue(int value);
int getMinValue() const { return _valueMin; }
void setMaxValue(int value);
int getMaxValue() const { return _valueMax; }
void setMinValue(uInt32 value);
void setMaxValue(uInt32 value);
uInt32 getMinValue() const { return _valueMin; }
uInt32 getMaxValue() const { return _valueMax; }
/**
Steps are not necessarily linear in a timeline, so we need info
@ -46,20 +46,19 @@ class TimeLineWidget : public ButtonWidget
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
void handleMouseWheel(int x, int y, int direction) override;
bool handleEvent(Event::Type event) override;
void drawWidget(bool hilite) override;
int valueToPos(int value);
int posToValue(int pos);
uInt32 valueToPos(uInt32 value);
uInt32 posToValue(uInt32 pos);
protected:
int _value, _stepValue__;
int _valueMin, _valueMax;
bool _isDragging;
int _labelWidth;
uInt32 _value;
uInt32 _valueMin, _valueMax;
bool _isDragging;
uInt32 _labelWidth;
IntArray _stepValue;
uIntArray _stepValue;
private:
// Following constructors and assignment operators not supported

View File

@ -22,8 +22,37 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeMachine::TimeMachine(OSystem& osystem)
: DialogContainer(osystem)
: DialogContainer(osystem),
myWidth(FrameBuffer::kFBMinW)
{
myBaseDialog = new TimeMachineDialog(myOSystem, *this,
FrameBuffer::kFBMinW, FrameBuffer::kFBMinH);
myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeMachine::requestResize()
{
uInt32 w, h;
myBaseDialog->getResizableBounds(w, h);
// If dialog is too large for given area, we need to resize it
// Otherwise, make it 80% of the allowable width
int newWidth = myWidth;
if(w < FrameBuffer::kFBMinW)
newWidth = w;
else if(myBaseDialog->getWidth() != 0.8 * w)
newWidth = uInt32(0.8 * w);
// Only re-create when absolutely necessary
if(myWidth != newWidth)
{
myWidth = newWidth;
Dialog* oldPtr = myBaseDialog;
delete myBaseDialog;
myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth);
Dialog* newPtr = myBaseDialog;
// Update the container stack; it may contain a reference to the old pointer
if(oldPtr != newPtr)
myDialogStack.replace(oldPtr, newPtr);
}
}

View File

@ -33,6 +33,15 @@ class TimeMachine : public DialogContainer
TimeMachine(OSystem& osystem);
virtual ~TimeMachine() = default;
/**
This dialog has an adjustable size. We need to make sure the
dialog can fit within the given bounds.
*/
void requestResize() override;
private:
int myWidth;
private:
// Following constructors and assignment operators not supported
TimeMachine() = delete;

View File

@ -36,7 +36,7 @@ using Common::Base;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
int max_w, int max_h)
int width)
: Dialog(osystem, parent)
{
const int BUTTON_W = 16, BUTTON_H = 14;
@ -75,23 +75,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
0b0110000110000110,
0
};
static uInt32 REWIND_10[BUTTON_H] =
{
0,
0b0000010000100110,
0b0000110001100110,
0b0001110011100110,
0b0011110111100110,
0b0111111111100110,
0b1111111111100110,
0b1111111111100110,
0b0111111111100110,
0b0011110111100110,
0b0001110011100110,
0b0000110001100110,
0b0000010000100110,
0
};
static uInt32 REWIND_1[BUTTON_H] =
{
0,
@ -126,23 +109,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
0b0011100011000000,
0
};
static uInt32 UNWIND_10[BUTTON_H] =
{
0,
0b0110010000100000,
0b0110011000110000,
0b0110011100111000,
0b0110011110111100,
0b0110011111111110,
0b0110011111111111,
0b0110011111111111,
0b0110011111111110,
0b0110011110111100,
0b0110011100111000,
0b0110011000110000,
0b0110010000100000,
0
};
static uInt32 UNWIND_ALL[BUTTON_H] =
{
0,
@ -170,7 +136,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
int xpos, ypos;
// Set real dimensions
_w = 20 * (buttonWidth + BUTTON_GAP) + 20;
_w = width; // Parent determines our width (based on window size)
_h = V_BORDER * 2 + rowHeight + buttonHeight + 2;
this->clearFlags(WIDGET_CLEARBG); // does only work combined with blending (0..100)!
@ -189,7 +155,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
// Add timeline
const uInt32 tl_h = myCurrentIdxWidget->getHeight() / 2,
tl_x = xpos + myCurrentIdxWidget->getWidth() + 8,
tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2,
tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2 - 1,
tl_w = myLastIdxWidget->getAbsX() - tl_x - 8;
myTimeline = new TimeLineWidget(this, font, tl_x, tl_y, tl_w, tl_h, "", 0, kTimeline);
myTimeline->setMinValue(0);
@ -208,10 +174,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
BUTTON_W, BUTTON_H, kRewindAll);
xpos += buttonWidth + BUTTON_GAP;
myRewind10Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_10,
BUTTON_W, BUTTON_H, kRewind10);
xpos += buttonWidth + BUTTON_GAP;
myRewind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_1,
BUTTON_W, BUTTON_H, kRewind1);
xpos += buttonWidth + BUTTON_GAP*2;
@ -224,10 +186,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
BUTTON_W, BUTTON_H, kUnwind1);
xpos += buttonWidth + BUTTON_GAP;
myUnwind10Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_10,
BUTTON_W, BUTTON_H, kUnwind10);
xpos += buttonWidth + BUTTON_GAP;
myUnwindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_ALL,
BUTTON_W, BUTTON_H, kUnwindAll);
xpos = myUnwindAllWidget->getRight() + BUTTON_GAP * 3;
@ -254,14 +212,15 @@ void TimeMachineDialog::loadConfig()
IntArray cycles = r.cyclesList();
// Set range and intervals for timeline
myTimeline->setMaxValue(cycles.size() - 1);
uInt32 maxValue = cycles.size() > 1 ? uInt32(cycles.size() - 1) : 0;
myTimeline->setMaxValue(maxValue);
myTimeline->setStepValues(cycles);
// Enable blending (only once is necessary)
if(!surface().attributes().blending)
{
surface().attributes().blending = true;
surface().attributes().blendalpha = 80;
surface().attributes().blendalpha = 92;
surface().applyAttributes();
}
@ -361,11 +320,11 @@ string TimeMachineDialog::getTimeString(uInt64 cycles)
const Int32 PAL_FREQ = 1182298; // ~76*312*50
const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second
uInt32 minutes = cycles / (freq * 60);
uInt32 minutes = uInt32(cycles / (freq * 60));
cycles -= minutes * (freq * 60);
uInt32 seconds = cycles / freq;
uInt32 seconds = uInt32(cycles / freq);
cycles -= seconds * freq;
uInt32 frames = cycles / (scanlines * 76);
uInt32 frames = uInt32(cycles / (scanlines * 76));
stringstream time;
time << Common::Base::toString(minutes, Common::Base::F_10_02) << ":";
@ -395,6 +354,7 @@ void TimeMachineDialog::handleWinds(Int32 numWinds)
myMessageWidget->setLabel((numWinds < 0 ? "(-" : "(+") + message + ")");
}
}
// Update time
myCurrentTimeWidget->setLabel(getTimeString(r.getCurrentCycles() - r.getFirstCycles()));
myLastTimeWidget->setLabel(getTimeString(r.getLastCycles() - r.getFirstCycles()));
@ -404,9 +364,7 @@ void TimeMachineDialog::handleWinds(Int32 numWinds)
myLastIdxWidget->setValue(r.getLastIdx());
// Enable/disable buttons
myRewindAllWidget->setEnabled(!r.atFirst());
myRewind10Widget->setEnabled(!r.atFirst());
myRewind1Widget->setEnabled(!r.atFirst());
myUnwindAllWidget->setEnabled(!r.atLast());
myUnwind10Widget->setEnabled(!r.atLast());
myUnwind1Widget->setEnabled(!r.atLast());
}

View File

@ -28,7 +28,7 @@ class TimeLineWidget;
class TimeMachineDialog : public Dialog
{
public:
TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int max_w, int max_h);
TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int width);
virtual ~TimeMachineDialog() = default;
private:
@ -61,10 +61,8 @@ class TimeMachineDialog : public Dialog
ButtonWidget* myPlayWidget;
ButtonWidget* myRewindAllWidget;
ButtonWidget* myRewind10Widget;
ButtonWidget* myRewind1Widget;
ButtonWidget* myUnwind1Widget;
ButtonWidget* myUnwind10Widget;
ButtonWidget* myUnwindAllWidget;
StaticTextWidget* myCurrentTimeWidget;

View File

@ -55,8 +55,8 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
VariantList items;
// Set real dimensions
_w = std::min(57 * fontWidth + HBORDER * 2, max_w);
_h = std::min((16-2) * (lineHeight + VGAP) + 14 + _th, max_h);
_w = std::min(55 * fontWidth + HBORDER * 2 + 8, max_w);
_h = std::min(14 * (lineHeight + VGAP) + 14 + _th, max_h);
// The tab widget
xpos = 2; ypos = 4;
@ -94,6 +94,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
SliderWidget* s = new SliderWidget(myTab, font, xpos, ypos - 1, swidth, lineHeight,
"TIA zoom", lwidth, 0, fontWidth * 4, "%");
s->setMinValue(200); s->setMaxValue(500);
s->setTickmarkInterval(3); // just for testing now; TODO: remove or redefine
wid.push_back(s);
ypos += lineHeight + VGAP;
@ -141,7 +142,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
"(*) Requires application restart");
// Move over to the next column
xpos += myFrameRate->getWidth() + 28;
xpos += myFrameRate->getWidth() + 16;
ypos = VBORDER;
// Fullscreen
@ -236,7 +237,7 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
CREATE_CUSTOM_SLIDERS(Fringe, "Fringing ");
CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding ");
xpos += myTVContrast->getWidth() + 40;
xpos += myTVContrast->getWidth() + 30;
ypos = VBORDER;
lwidth = font.getStringWidth("Intensity ");
@ -389,7 +390,6 @@ void VideoDialog::saveConfig()
// TIA Filter
instance().settings().setValue("tia.zoom",
myTIAZoom->getSelectedTag().toString());
instance().frameBuffer().setZoomMode(instance().settings().getInt("tia.zoom"));
// TIA Palette
instance().settings().setValue("palette",

View File

@ -638,7 +638,8 @@ SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font,
_valueLabelGap(valueLabelGap),
_valueLabelWidth(valueLabelWidth),
_valueLabel(""),
_valueUnit(valueUnit)
_valueUnit(valueUnit),
_numIntervals(0)
{
_flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE;
_bgcolor = kDlgColor;
@ -721,6 +722,13 @@ void SliderWidget::setValueUnit(const string& valueUnit)
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SliderWidget::setTickmarkInterval(int numIntervals)
{
_numIntervals = numIntervals;
setDirty();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SliderWidget::handleMouseMoved(int x, int y)
{
@ -816,6 +824,30 @@ void SliderWidget::drawWidget(bool hilite)
// Draw the 'bar'
s.fillRect(x, y, p, h,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);
// Draw the 'tickmarks'
for(int i = 1; i < _numIntervals; ++i)
{
int xt = x + (_w - _labelWidth - _valueLabelGap - _valueLabelWidth) * i / _numIntervals - 1;
uInt32 color;
if(isEnabled())
{
if(xt > x + p)
color = hilite ? kSliderColorHi : kSliderColor;
else
color = hilite ? kSliderBGColorHi : kSliderBGColor;
}
else
{
if(xt > x + p)
color = kColor;
else
color = kSliderBGColorLo;
}
s.vLine(xt, y + h / 2, y + h - 1, color);
}
// Draw the 'handle'
s.fillRect(x + p, y - 2, 2, h + 4,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);

View File

@ -328,6 +328,8 @@ class SliderWidget : public ButtonWidget
const string& getValueLabel() const { return _valueLabel; }
void setValueUnit(const string& valueUnit);
void setTickmarkInterval(int numIntervals);
protected:
void handleMouseMoved(int x, int y) override;
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
@ -349,6 +351,7 @@ class SliderWidget : public ButtonWidget
string _valueUnit;
int _valueLabelWidth;
int _valueLabelGap;
int _numIntervals;
private:
// Following constructors and assignment operators not supported

View File

@ -1,8 +1,8 @@
/* Localized versions of Info.plist keys */
CFBundleName = "Stella";
CFBundleShortVersionString = "Stella version 5.0.2";
CFBundleGetInfoString = "Stella version 5.0.2";
CFBundleShortVersionString = "Stella version 5.1";
CFBundleGetInfoString = "Stella version 5.1";
NSHumanReadableCopyright = "Stella MacOS X version by Stephen Anthony and Mark Grebe.";
"Atari 2600 Cartridge File" = "Atari 2600 Cartridge File";

View File

@ -53,7 +53,7 @@
<key>CFBundleSignature</key>
<string>StLa</string>
<key>CFBundleVersion</key>
<string>5.0.2</string>
<string>5.1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersionByArchitecture</key>

View File

@ -1,5 +1,5 @@
%define name stella
%define version 5.0.2
%define version 5.1
%define rel 1
%define enable_sound 1
@ -101,6 +101,9 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
%_datadir/icons/large/%{name}.png
%changelog
* Sun Feb 04 2018 Stephen Anthony <stephena@users.sf.net> 5.1-1
- Version 5.1 release
* Sun Aug 20 2017 Stephen Anthony <stephena@users.sf.net> 5.0.2-1
- Version 5.0.2 release

View File

@ -36,8 +36,8 @@ IDI_ICON ICON "stella.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,0,2,0
PRODUCTVERSION 5,0,2,0
FILEVERSION 5,1,0,0
PRODUCTVERSION 5,1,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -55,12 +55,12 @@ BEGIN
VALUE "Comments", "The multi-platform Atari 2600 emulator. Stella is released under the GPLv2."
VALUE "CompanyName", "The Stella Team (https://stella-emu.github.io)"
VALUE "FileDescription", "Stella"
VALUE "FileVersion", "5.0.2"
VALUE "FileVersion", "5.1"
VALUE "InternalName", "Stella"
VALUE "LegalCopyright", "Copyright (C) 1995-2018 The Stella Team"
VALUE "OriginalFilename", "Stella.exe"
VALUE "ProductName", "Stella"
VALUE "ProductVersion", "5.0.2"
VALUE "ProductVersion", "5.1"
END
END
BLOCK "VarFileInfo"