Merge branch 'master' into feature/precise-audio

This commit is contained in:
Christian Speckner 2018-02-12 23:32:03 +01:00
commit 5c1bd83904
42 changed files with 518 additions and 312 deletions

View File

@ -1,3 +1,12 @@
5.1 to 5.2: (MMM d, 2018)
* Extra functionality for Time Machine dialog (start/stop recording;
minor fixes; TODO button and initial key repeats...)
* Fixes for collision corner cases (during HBlank)
* UI modernization (new widget look, dialog titles added, dialogs refactored)
5.0.2 to 5.1: (February 4, 2018)
* Added "Time Machine" mode, which automatically creates save states

View File

@ -44,20 +44,11 @@ class FixedStack
bool full() const { return _size >= CAPACITY; }
T top() const { return _stack[_size - 1]; }
T get(uInt32 pos) { return _stack[pos]; };
T get(uInt32 pos) { return _stack[pos]; }
void push(const T& x) { _stack[_size++] = x; }
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

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

View File

@ -26,8 +26,7 @@ PaddleWidget::PaddleWidget(GuiObject* boss, const GUI::Font& font,
bool leftport = isLeftPort();
const string& label = getHeader();
const int fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
const int fontHeight = font.getFontHeight(),
lineHeight = font.getLineHeight();
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Paddles)");

View File

@ -301,19 +301,19 @@ 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);
return;
break;
case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true);
return;
break;
case KBDK_DOWN: // Alt-down rewinds to start of list
enterTimeMachineMenuMode(1000, false);
return;
break;
case KBDK_UP: // Alt-up rewinds to end of list
enterTimeMachineMenuMode(1000, true);
return;
break;
// These can work in pause mode too
case KBDK_EQUALS:
@ -2151,13 +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);
// hande winds and display wind message (numWinds != 0) in time machine dialog
myOSystem.timeMachine().setEnterWinds(unwind ? numWinds : -numWinds);
// TODO: display last wind message (numWinds != 0) in time machine dialog
enterMenuMode(EventHandlerState::TIMEMACHINE);
}

View File

@ -268,14 +268,12 @@ void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
break;
case FrameStyle::Dashed:
uInt32 i, skip, lwidth = 1;
for(i = x; i < x + w; i += 2)
for(uInt32 i = x; i < x + w; i += 2)
{
hLine(i, y, i, color);
hLine(i, y + h - 1, i, color);
}
for(i = y; i < y + h; i += 2)
for(uInt32 i = y; i < y + h; i += 2)
{
vLine(x, i, i, color);
vLine(x + w - 1, i, i, color);

View File

@ -385,9 +385,8 @@ void FrameBuffer::drawFrameStats()
int xPos = XPOS;
myStatsMsg.surface->invalidate();
string bsinfo = info.BankSwitch +
(myOSystem.settings().getBool("dev.settings") ? "| Developer" : "");
// draw shadowed text
// draw scanlines
color = myOSystem.console().tia().scanlinesLastFrame() != myLastScanlines ?
uInt32(kDbgColorRed) : myStatsMsg.color;
std::snprintf(msg, 30, "%3u", myOSystem.console().tia().scanlinesLastFrame());
@ -395,16 +394,20 @@ void FrameBuffer::drawFrameStats()
myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor);
xPos += font().getStringWidth(msg);
// draw frequency
std::snprintf(msg, 30, " => %s", info.DisplayFormat.c_str());
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
xPos += font().getStringWidth(msg);
std::snprintf(msg, 30, " @ %5.2ffps", myOSystem.console().getFramerate());
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
// draw bankswitching type
string bsinfo = info.BankSwitch +
(myOSystem.settings().getBool("dev.settings") ? "| Developer" : "");
myStatsMsg.surface->drawString(font(), bsinfo, XPOS, YPOS + font().getFontHeight(),
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
@ -1016,7 +1019,7 @@ uInt32 FrameBuffer::ourGUIColors[3][kNumColors-256] = {
0x20a020, 0x00ff00, // scrollbar
0x20a020, 0x00ff00, 0x404040, 0x686868, 0x404040, // slider
0xc80000, 0x00ff00, 0xc8c8ff, 0xc80000, // debugger
0x20a020, 0x20a020, 0x000000, 0x686868, 0x404040 // other
0x00ff00, 0x20a020, 0x000000, 0x686868, 0x404040 // other
},
// Light
{ 0x808080, 0x000000, 0xc0c0c0, 0xe1e1e1, 0x333333, // base

View File

@ -213,6 +213,56 @@ void OSystem::setConfigPaths()
mySettings->setValue("propsfile", node.getShortPath());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet& OSystem::propSet(const string& md5)
{
FilesystemNode node = FilesystemNode();
return propSet(md5, node);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet& OSystem::propSet(const string& md5, const FilesystemNode& node)
{
if(md5 == EmptyString)
return *myPropSet;
else if(md5 == myGamePropSetMD5)
return *myGamePropSet;
else if (!node.exists())
return *myPropSet;
// Get a valid set of game specific properties
Properties props;
string path = myBaseDir + node.getNameWithExt(".pro");
// Create a properties set based on ROM name
FilesystemNode propNode = FilesystemNode(path);
myGamePropertiesFile = propNode.getPath();
myGamePropSet = make_unique<PropertiesSet>(myGamePropertiesFile);
// Check if game specific property file exists and has matching md5
if(myGamePropSet->size() && myGamePropSet->getMD5(md5, props))
{
myGamePropSetMD5 = md5;
return *myGamePropSet;
}
else
{
myGamePropSetMD5 = "";
return *myPropSet;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::saveGamePropSet(const string& md5)
{
if(myGamePropSet->size() && md5 == myGamePropSetMD5)
{
myGamePropSet->save(myGamePropertiesFile);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void OSystem::setBaseDir(const string& basedir)
{
@ -428,8 +478,7 @@ void OSystem::logMessage(const string& message, uInt8 level)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<Console>
OSystem::openConsole(const FilesystemNode& romfile, string& md5)
unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string& md5)
{
unique_ptr<Console> console;
@ -441,8 +490,15 @@ OSystem::openConsole(const FilesystemNode& romfile, string& md5)
// Get a valid set of properties, including any entered on the commandline
// For initial creation of the Cart, we're only concerned with the BS type
Properties props;
myPropSet->getMD5(md5, props);
// Load and use game specific props if existing
FilesystemNode node = FilesystemNode(romfile);
string path = myBaseDir + node.getNameWithExt(".pro");
PropertiesSet& propset = propSet(md5, romfile);
propset.getMD5(md5, props);
// Local helper method
auto CMDLINE_PROPS_UPDATE = [&](const string& name, PropertyType prop)
{
const string& s = mySettings->getString(name);
@ -462,12 +518,12 @@ OSystem::openConsole(const FilesystemNode& romfile, string& md5)
// and that the md5 (and hence the cart) has changed
if(props.get(Cartridge_MD5) != cartmd5)
{
if(!myPropSet->getMD5(cartmd5, props))
if(!propset.getMD5(cartmd5, props))
{
// Cart md5 wasn't found, so we create a new props for it
props.set(Cartridge_MD5, cartmd5);
props.set(Cartridge_Name, props.get(Cartridge_Name)+cart->multiCartID());
myPropSet->insert(props, false);
propset.insert(props, false);
}
}

View File

@ -107,7 +107,13 @@ class OSystem
@return The properties set object
*/
PropertiesSet& propSet() const { return *myPropSet; }
PropertiesSet& propSet(const string& md5 = EmptyString);
PropertiesSet& propSet(const string& md5, const FilesystemNode& node);
/**
Save the game specific property file.
*/
void saveGamePropSet(const string& md5);
/**
Get the console of the system. The console won't always exist,
@ -427,6 +433,12 @@ class OSystem
// Pointer to the PropertiesSet object
unique_ptr<PropertiesSet> myPropSet;
// Pointer to the game's PropertiesSet object
unique_ptr<PropertiesSet> myGamePropSet;
// MD5 of the currently loaded game PropertiesSet object
string myGamePropSetMD5;
// Pointer to the (currently defined) Console object
unique_ptr<Console> myConsole;
@ -480,6 +492,7 @@ class OSystem
string myConfigFile;
string myPaletteFile;
string myPropertiesFile;
string myGamePropertiesFile;
FilesystemNode myRomFile;
string myRomMD5;

View File

@ -112,6 +112,11 @@ class PropertiesSet
*/
void print() const;
/**
Return the size of the myExternalProps list
*/
uInt32 size() { return myExternalProps.size(); }
private:
using PropsList = std::map<string, Properties>;

View File

@ -40,6 +40,7 @@ void Ball::reset()
myIsEnabledNew = false;
myIsEnabled = false;
myIsDelaying = false;
myIsVisible = false;
myHmmClocks = 0;
myCounter = 0;
myIsMoving = false;
@ -49,8 +50,7 @@ void Ball::reset()
myIsRendering = false;
myDebugEnabled = false;
myRenderCounter = 0;
updateEnabled();
myIsEnabled = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -62,7 +62,10 @@ void Ball::enabl(uInt8 value)
if (myIsEnabledNew != enabledNewOldValue && !myIsDelaying) {
myTIA->flushLineCache();
updateEnabled();
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
myTIA->updateCollision();
}
}
@ -173,9 +176,8 @@ bool Ball::movementTick(uInt32 clock, bool apply)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Ball::tick(bool isReceivingMclock)
{
collision = (myIsRendering && myRenderCounter >= 0 && myIsEnabled) ?
myCollisionMaskEnabled :
myCollisionMaskDisabled;
myIsVisible = myIsRendering && myRenderCounter >= 0;
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
bool starfieldEffect = myIsMoving && isReceivingMclock;
@ -207,6 +209,13 @@ void Ball::tick(bool isReceivingMclock)
myCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Ball::nextLine()
{
myIsVisible = myIsRendering && myRenderCounter >= 0;
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Ball::setENABLOld(bool enabled)
{
@ -233,6 +242,9 @@ void Ball::shuffleStatus()
void Ball::updateEnabled()
{
myIsEnabled = !myIsSuppressed && (myIsDelaying ? myIsEnabledOld : myIsEnabledNew);
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
myTIA->updateCollision();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -293,6 +305,7 @@ bool Ball::save(Serializer& out) const
out.putBool(myIsEnabled);
out.putBool(myIsSuppressed);
out.putBool(myIsDelaying);
out.putBool(myIsVisible);
out.putByte(myHmmClocks);
out.putByte(myCounter);
@ -335,6 +348,7 @@ bool Ball::load(Serializer& in)
myIsEnabled = in.getBool();
myIsSuppressed = in.getBool();
myIsDelaying = in.getBool();
myIsVisible = in.getBool();
myHmmClocks = in.getByte();
myCounter = in.getByte();

View File

@ -62,6 +62,8 @@ class Ball : public Serializable
void tick(bool isReceivingMclock = true);
void nextLine();
bool isOn() const { return (collision & 0x8000); }
uInt8 getColor() const { return myColor; }
@ -105,6 +107,7 @@ class Ball : public Serializable
bool myIsEnabled;
bool myIsSuppressed;
bool myIsDelaying;
bool myIsVisible;
uInt8 myHmmClocks;
uInt8 myCounter;

View File

@ -47,12 +47,12 @@ void Missile::reset()
myWidth = 1;
myEffectiveWidth = 1;
myIsRendering = false;
myIsVisible = false;
myRenderCounter = 0;
myColor = myObjectColor = myDebugColor = 0;
myDebugEnabled = false;
collision = myCollisionMaskDisabled;
updateEnabled();
myIsEnabled = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -62,9 +62,11 @@ void Missile::enam(uInt8 value)
myEnam = (value & 0x02) > 0;
if (oldEnam != myEnam) myTIA->flushLineCache();
if (oldEnam != myEnam) {
myTIA->flushLineCache();
updateEnabled();
updateEnabled();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -166,41 +168,43 @@ bool Missile::movementTick(uInt8 clock, uInt8 hclock, bool apply)
if (clock == myHmmClocks) myIsMoving = false;
if (myIsMoving && apply) tick(hclock);
if (myIsMoving && apply) tick(hclock, false);
return myIsMoving;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Missile::tick(uInt8 hclock)
void Missile::tick(uInt8 hclock, bool isReceivingMclock)
{
const bool render =
myIsVisible =
myIsRendering &&
(myRenderCounter >= 0 || (myIsMoving && myRenderCounter == -1 && myWidth < 4 && ((hclock + 1) % 4 == 3))) &&
myIsEnabled;
(myRenderCounter >= 0 || (myIsMoving && isReceivingMclock && myRenderCounter == -1 && myWidth < 4 && ((hclock + 1) % 4 == 3)));
collision = render ? myCollisionMaskEnabled : myCollisionMaskDisabled;
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
if (myDecodes[myCounter] && !myResmp) {
myIsRendering = true;
myRenderCounter = Count::renderCounterOffset;
} else if (myIsRendering) {
if (myIsMoving && myRenderCounter == -1) {
if (myRenderCounter == -1) {
if (myIsMoving && isReceivingMclock) {
switch ((hclock + 1) % 4) {
case 3:
myEffectiveWidth = myWidth == 1 ? 2 : myWidth;
if (myWidth < 4) myRenderCounter++;
break;
switch ((hclock + 1) % 4) {
case 3:
myEffectiveWidth = myWidth == 1 ? 2 : myWidth;
if (myWidth < 4) myRenderCounter++;
break;
case 2:
myEffectiveWidth = 0;
break;
case 2:
myEffectiveWidth = 0;
break;
default:
myEffectiveWidth = myWidth;
break;
default:
myEffectiveWidth = myWidth;
break;
}
} else {
myEffectiveWidth = myWidth;
}
}
@ -210,6 +214,13 @@ void Missile::tick(uInt8 hclock)
if (++myCounter >= 160) myCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Missile::nextLine()
{
myIsVisible = myIsRendering && (myRenderCounter >= 0);
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Missile::setColor(uInt8 color)
{
@ -246,6 +257,9 @@ void Missile::applyColorLoss()
void Missile::updateEnabled()
{
myIsEnabled = !myIsSuppressed && myEnam && !myResmp;
collision = (myIsVisible && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
myTIA->updateCollision();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -308,6 +322,7 @@ bool Missile::save(Serializer& out) const
out.putByte(myEffectiveWidth);
out.putByte(myLastMovementTick);
out.putBool(myIsVisible);
out.putBool(myIsRendering);
out.putByte(myRenderCounter);
@ -350,6 +365,7 @@ bool Missile::load(Serializer& in)
myEffectiveWidth = in.getByte();
myLastMovementTick = in.getByte();
myIsVisible = in.getBool();
myIsRendering = in.getBool();
myRenderCounter = in.getByte();

View File

@ -50,7 +50,9 @@ class Missile : public Serializable
bool movementTick(uInt8 clock, uInt8 hclock, bool apply);
void tick(uInt8 hclock);
void tick(uInt8 hclock, bool isReceivingMclock = true);
void nextLine();
void setColor(uInt8 color);
@ -103,6 +105,7 @@ class Missile : public Serializable
uInt8 myLastMovementTick;
bool myIsRendering;
bool myIsVisible;
Int8 myRenderCounter;
const uInt8* myDecodes;

View File

@ -52,9 +52,9 @@ void Player::reset()
mySampleCounter = 0;
myDividerPending = 0;
myDividerChangeCounter = -1;
myPattern = 0;
setDivider(1);
updatePattern();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -309,6 +309,15 @@ void Player::tick()
if (++myCounter >= 160) myCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Player::nextLine()
{
if (!myIsRendering || myRenderCounter < myRenderCounterTripPoint)
collision = myCollisionMaskDisabled;
else
collision = (myPattern & (1 << mySampleCounter)) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Player::shufflePatterns()
{
@ -372,6 +381,11 @@ void Player::updatePattern()
((myPattern & 0x80) >> 7)
);
}
if (myIsRendering && myRenderCounter >= myRenderCounterTripPoint) {
collision = (myPattern & (1 << mySampleCounter)) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
myTIA->updateCollision();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -62,6 +62,9 @@ class Player : public Serializable
bool movementTick(uInt32 clock, bool apply);
void tick();
void nextLine();
uInt8 getClock() const { return myCounter; }
bool isOn() const { return (collision & 0x8000); }

View File

@ -204,6 +204,12 @@ void Playfield::tick(uInt32 x)
collision = currentPixel ? myCollisionMaskEnabled : myCollisionMaskDisabled;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Playfield::nextLine()
{
collision = myCollisionMaskDisabled;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Playfield::applyColors()
{

View File

@ -59,6 +59,8 @@ class Playfield : public Serializable
void tick(uInt32 x);
void nextLine();
bool isOn() const { return (collision & 0x8000); }
uInt8 getColor() const;

View File

@ -1273,7 +1273,6 @@ void TIA::nextLine()
cloneLastLine();
}
myPlayfield.tick(0);
myHctr = 0;
if (!myMovementInProgress && myLinesSinceChange < 2) myLinesSinceChange++;
@ -1282,6 +1281,12 @@ void TIA::nextLine()
myHctrDelta = 0;
myFrameManager->nextLine();
myMissile0.nextLine();
myMissile1.nextLine();
myPlayer0.nextLine();
myPlayer1.nextLine();
myBall.nextLine();
myPlayfield.nextLine();
if (myFrameManager->isRendering() && myFrameManager->getY() == 0) flushLineCache();

View File

@ -415,6 +415,11 @@ class TIA : public Device
*/
void flushLineCache();
/**
* Update the collision bitfield.
*/
void updateCollision();
/**
Create a new delayQueueIterator for the debugger.
*/
@ -511,11 +516,6 @@ class TIA : public Device
*/
void applyRsync();
/**
* Update the collision bitfield.
*/
void updateCollision();
/**
* Render the current pixel into the framebuffer.
*/

View File

@ -42,9 +42,7 @@ AudioDialog::AudioDialog(OSystem& osystem, DialogContainer& parent,
const int INDENT = 20;
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
fontHeight = font.getFontHeight();
int xpos, ypos;
int lwidth = font.getStringWidth("Sample Size (*) "),
pwidth = font.getStringWidth("512 bytes");

View File

@ -33,10 +33,7 @@ ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font,
myComboEvent(Event::NoType)
{
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
fontWidth = font.getMaxCharWidth();
int xpos, ypos;
WidgetArray wid;

View File

@ -27,13 +27,10 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent)
: Dialog(osystem, parent)
: Dialog(osystem, parent, osystem.frameBuffer().font(), "Commands")
{
const GUI::Font& font = instance().frameBuffer().font();
initTitle(font, "Commands");
const int buttonWidth = font.getStringWidth("Right Diff B") + 20,
buttonHeight = font.getLineHeight() + 6,
const int buttonWidth = _font.getStringWidth("Right Diff B") + 20,
buttonHeight = _font.getLineHeight() + 6,
rowHeight = buttonHeight + 8;
// Set real dimensions
@ -46,7 +43,7 @@ CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent)
auto ADD_CD_BUTTON = [&](const string& label, int cmd)
{
ButtonWidget* bw = new ButtonWidget(this, font, xoffset, yoffset,
ButtonWidget* bw = new ButtonWidget(this, _font, xoffset, yoffset,
buttonWidth, buttonHeight, label, cmd);
xoffset += buttonWidth + 8;
return bw;

View File

@ -28,7 +28,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font,
const VariantList& items, int cmd, int width)
: Dialog(boss->instance(), boss->parent()),
: Dialog(boss->instance(), boss->parent(), font),
CommandSender(boss),
_rowHeight(font.getLineHeight()),
_firstEntry(0),
@ -39,7 +39,6 @@ ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font,
_isScrolling(false),
_scrollUpColor(kColor),
_scrollDnColor(kColor),
_font(font),
_cmd(cmd),
_xorig(0),
_yorig(0),

View File

@ -120,7 +120,6 @@ class ContextMenu : public Dialog, public CommandSender
bool _isScrolling;
uInt32 _scrollUpColor, _scrollDnColor;
const GUI::Font& _font;
int _cmd;
uInt32 _xorig, _yorig;

View File

@ -44,13 +44,10 @@
* ...
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dialog::Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font, const string& title,
int x, int y, int w, int h)
Dialog::Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font,
const string& title, int x, int y, int w, int h)
: GuiObject(instance, parent, *this, x, y, w, h),
_font(&font),
_title(title),
_th(0),
_font(font),
_mouseWidget(nullptr),
_focusedWidget(nullptr),
_dragWidget(nullptr),
@ -58,30 +55,19 @@ Dialog::Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font
_cancelWidget(nullptr),
_visible(false),
_processCancel(false),
_title(title),
_th(0),
_surface(nullptr),
_tabID(0),
_flags(WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG)
{
initTitle(font, title);
setTitle(title);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dialog::Dialog(OSystem& instance, DialogContainer& parent,
int x, int y, int w, int h)
: GuiObject(instance, parent, *this, x, y, w, h),
_font(nullptr),
_title(""),
_th(0),
_fh(0),
_mouseWidget(nullptr),
_focusedWidget(nullptr),
_dragWidget(nullptr),
_okWidget(nullptr),
_cancelWidget(nullptr),
_visible(false),
_processCancel(false),
_surface(nullptr),
_tabID(0),
_flags(WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG)
: Dialog(instance, parent, instance.frameBuffer().font(), "", x, y, w, h)
{
}
@ -133,27 +119,16 @@ void Dialog::close(bool refresh)
parent().removeDialog();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Dialog::initTitle(const GUI::Font& font, const string& title)
{
_font = &font;
_fh = font.getLineHeight();
setTitle(title);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Dialog::setTitle(const string& title)
{
if(_font != nullptr)
{
_title = title;
_h -= _th;
if(title.empty())
_th = 0;
else
_th = _fh + 4;
_h += _th;
}
_title = title;
_h -= _th;
if(title.empty())
_th = 0;
else
_th = _font.getLineHeight() + 4;
_h += _th;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -326,8 +301,8 @@ void Dialog::drawDialog()
{
// dialog is still on top if e.g a ContextMenu is opened
bool onTop = parent().myDialogStack.top() == this
|| parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
&& !parent().myDialogStack.top()->hasTitle();
|| (parent().myDialogStack.get(parent().myDialogStack.size() - 2) == this
&& !parent().myDialogStack.top()->hasTitle());
if(_flags & WIDGET_CLEARBG)
{
@ -336,7 +311,7 @@ void Dialog::drawDialog()
if(_th)
{
s.fillRect(_x, _y, _w, _th, onTop ? kColorTitleBar : kColorTitleBarLo);
s.drawString(*_font, _title, _x + 10, _y + 2 + 1, _font->getStringWidth(_title),
s.drawString(_font, _title, _x + 10, _y + 2 + 1, _font.getStringWidth(_title),
onTop ? kColorTitleText : kColorTitleTextLo);
}
}

View File

@ -46,8 +46,8 @@ class Dialog : public GuiObject
public:
Dialog(OSystem& instance, DialogContainer& parent,
int x = 0, int y = 0, int w = 0, int h = 0);
Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font, const string& title,
int x = 0, int y = 0, int w = 0, int h = 0);
Dialog(OSystem& instance, DialogContainer& parent, const GUI::Font& font,
const string& title = "", int x = 0, int y = 0, int w = 0, int h = 0);
virtual ~Dialog();
@ -129,8 +129,6 @@ class Dialog : public GuiObject
void processCancelWithoutWidget(bool state) { _processCancel = state; }
void initTitle(const GUI::Font& font, const string& title);
private:
void buildCurrentFocusList(int tabID = -1);
bool handleNavEvent(Event::Type e);
@ -138,18 +136,19 @@ class Dialog : public GuiObject
bool cycleTab(int direction);
protected:
const GUI::Font& _font;
Widget* _mouseWidget;
Widget* _focusedWidget;
Widget* _dragWidget;
Widget* _defaultWidget;
Widget* _okWidget;
Widget* _cancelWidget;
bool _visible;
bool _processCancel;
string _title;
int _th;
const GUI::Font* _font;
int _fh;
Common::FixedStack<shared_ptr<FBSurface>> mySurfaceStack;

View File

@ -47,7 +47,6 @@ GameInfoDialog::GameInfoDialog(
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
const int vBorder = 8;
const int hBorder = 8;
@ -349,7 +348,7 @@ void GameInfoDialog::loadConfig()
const string& md5 = instance().launcher().selectedRomMD5();
if(md5 != "")
{
instance().propSet().getMD5(md5, myGameProperties);
instance().propSet(md5).getMD5(md5, myGameProperties);
myPropertiesLoaded = true;
loadView();
}
@ -487,10 +486,13 @@ void GameInfoDialog::saveConfig()
myPPBlend->getValueLabel());
// Determine whether to add or remove an entry from the properties set
const string& md5 = myGameProperties.get(Cartridge_MD5);
if(myDefaultsSelected)
instance().propSet().removeMD5(myGameProperties.get(Cartridge_MD5));
instance().propSet(md5).removeMD5(myGameProperties.get(Cartridge_MD5));
else
instance().propSet().insert(myGameProperties);
instance().propSet(md5).insert(myGameProperties);
instance().saveGamePropSet(myGameProperties.get(Cartridge_MD5));
// In any event, inform the Console
if(instance().hasConsole())
@ -502,7 +504,7 @@ void GameInfoDialog::setDefaults()
{
// Load the default properties
string md5 = myGameProperties.get(Cartridge_MD5);
instance().propSet().getMD5(md5, myGameProperties, true);
instance().propSet(md5).getMD5(md5, myGameProperties, true);
// Reload the current dialog
loadView();

View File

@ -36,7 +36,6 @@ GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font)
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
int xpos, ypos;
int lwidth = font.getStringWidth("Right Difficulty "),

View File

@ -45,7 +45,6 @@ InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent,
{
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
const int vBorder = 4;
int xpos, ypos, tabID;

View File

@ -349,7 +349,7 @@ void LauncherDialog::loadRomInfo()
// Get the properties for this entry
Properties props;
instance().propSet().getMD5WithInsert(node, myGameList->md5(item), props);
instance().propSet(myGameList->md5(item), node).getMD5WithInsert(node, myGameList->md5(item), props);
myRomInfoWidget->setProperties(props);
}

View File

@ -48,16 +48,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
GuiObject* boss, int max_w, int max_h, stellaMode mode)
: Dialog(osystem, parent),
: Dialog(osystem, parent, osystem.frameBuffer().font(), "Options"),
myMode(mode),
_boss(boss)
{
const GUI::Font& font = instance().frameBuffer().font();
initTitle(font, "Options");
const int buttonWidth = font.getStringWidth("Game Properties" + ELLIPSIS) + 20,
buttonHeight = font.getLineHeight() + 6,
rowHeight = font.getLineHeight() + 10;
const int buttonWidth = _font.getStringWidth("Game Properties" + ELLIPSIS) + 20,
buttonHeight = _font.getLineHeight() + 6,
rowHeight = _font.getLineHeight() + 10;
const int VBORDER = 10 + _th;
_w = 2 * buttonWidth + 30;
@ -69,7 +66,7 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
auto ADD_OD_BUTTON = [&](const string& label, int cmd)
{
ButtonWidget* bw = new ButtonWidget(this, font, xoffset, yoffset,
ButtonWidget* bw = new ButtonWidget(this, _font, xoffset, yoffset,
buttonWidth, buttonHeight, label, cmd);
yoffset += rowHeight;
return bw;
@ -128,21 +125,21 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
addCancelWidget(b);
// Now create all the dialogs attached to each menu button
myVideoDialog = make_unique<VideoDialog>(osystem, parent, font, max_w, max_h);
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, 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);
myVideoDialog = make_unique<VideoDialog>(osystem, parent, _font, max_w, max_h);
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, 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
myCheatCodeDialog = make_unique<CheatCodeDialog>(osystem, parent, font);
myCheatCodeDialog = make_unique<CheatCodeDialog>(osystem, parent, _font);
#endif
myLoggerDialog = make_unique<LoggerDialog>(osystem, parent, font, max_w, max_h);
myDeveloperDialog = make_unique<DeveloperDialog>(osystem, parent, font, max_w, max_h);
myHelpDialog = make_unique<HelpDialog>(osystem, parent, font);
myAboutDialog = make_unique<AboutDialog>(osystem, parent, font);
myLoggerDialog = make_unique<LoggerDialog>(osystem, parent, _font, max_w, max_h);
myDeveloperDialog = make_unique<DeveloperDialog>(osystem, parent, _font, max_w, max_h);
myHelpDialog = make_unique<HelpDialog>(osystem, parent, _font);
myAboutDialog = make_unique<AboutDialog>(osystem, parent, _font);
addToFocusList(wid);

View File

@ -263,11 +263,6 @@ void TabWidget::drawWidget(bool hilite)
FBSurface& s = dialog().surface();
const int left1 = _x + 1;
const int right1 = _x + kTabLeftOffset + _activeTab * (_tabWidth + kTabSpacing);
const int left2 = right1 + _tabWidth;
const int right2 = _x + _w - 2;
// Iterate over all tabs and draw them
int i, x = _x + kTabLeftOffset;
for (i = 0; i < int(_tabs.size()); ++i)

View File

@ -25,6 +25,9 @@
#include "TimeLineWidget.hxx"
const int HANDLE_W = 3;
const int HANDLE_H = 3; // size above/below the slider
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h,
@ -85,7 +88,7 @@ void TimeLineWidget::setStepValues(const IntArray& steps)
if(steps.size() > _stepValue.capacity())
_stepValue.reserve(2 * steps.size());
double scale = (_w - _labelWidth - 2) / double(steps.back());
double scale = (_w - _labelWidth - 2 - HANDLE_W*0) / double(steps.back());
// 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)
@ -93,7 +96,7 @@ void TimeLineWidget::setStepValues(const IntArray& steps)
// 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);
_stepValue.push_back(_w - _labelWidth - 2 - HANDLE_W*0);
}
else
_stepValue.push_back(0);
@ -142,48 +145,64 @@ void TimeLineWidget::drawWidget(bool hilite)
{
FBSurface& s = _boss->dialog().surface();
#ifndef FLAT_UI
// Draw the label, if any
if(_labelWidth > 0)
s.drawString(_font, _label, _x, _y + 2, _labelWidth,
isEnabled() ? kTextColor : kColor, TextAlign::Right);
isEnabled() ? kTextColor : kColor, TextAlign::Left);
int p = valueToPos(_value),
x = _x + _labelWidth,
w = _w - _labelWidth;
// Frame the handle
const int HANDLE_W2 = (HANDLE_W + 1) / 2;
s.hLine(x + p - HANDLE_W2, _y + 0, x + p - HANDLE_W2 + HANDLE_W, kColorInfo);
s.vLine(x + p - HANDLE_W2, _y + 1, _y + _h - 2, kColorInfo);
s.hLine(x + p - HANDLE_W2 + 1, _y + _h - 1, x + p - HANDLE_W2 + 1 + HANDLE_W, kBGColor);
s.vLine(x + p - HANDLE_W2 + 1 + HANDLE_W, _y + 1, _y + _h - 2, kBGColor);
// Frame the box
s.hLine(x, _y + HANDLE_H, x + w - 2, kColorInfo);
s.vLine(x, _y + HANDLE_H, _y + _h - 2 - HANDLE_H, kColorInfo);
s.hLine(x + 1, _y + _h - 1 - HANDLE_H, x + w - 1, kBGColor);
s.vLine(x + w - 1, _y + 1 + HANDLE_H, _y + _h - 2 - HANDLE_H, kBGColor);
// Draw the box
s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor);
// Fill the box
s.fillRect(_x + _labelWidth + 1, _y + 1, _w - _labelWidth - 2, _h - 2,
!isEnabled() ? kBGColorHi : kWidColor);
s.fillRect(x + 1, _y + 1 + HANDLE_H, w - 2, _h - 2 - HANDLE_H * 2,
!isEnabled() ? kSliderBGColorLo : hilite ? kSliderBGColorHi : kSliderBGColor);
// Draw the 'bar'
int vp = valueToPos(_value);
s.fillRect(_x + _labelWidth + 1, _y + 1, vp, _h - 2,
s.fillRect(x + 1, _y + 1 + HANDLE_H, p, _h - 2 - HANDLE_H * 2,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);
// add 4 tickmarks for 5 intervals
// 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);
int xt = x + valueToPos(idx - 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 - 2 - HANDLE_H, color);
}
}
#else
// Draw the label, if any
if(_labelWidth > 0)
s.drawString(_font, _label, _x, _y + 2, _labelWidth,
isEnabled() ? kTextColor : kColor, TextAlign::Left);
// Draw the box
s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, isEnabled() && hilite ? kSliderColorHi : kShadowColor);
// Fill the box
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,
// Draw the handle
s.fillRect(x + p + 1 - HANDLE_W2, _y + 1, HANDLE_W, _h - 2,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -47,12 +47,25 @@ void TimeMachine::requestResize()
{
myWidth = newWidth;
Dialog* oldPtr = myBaseDialog;
Int32 enterWinds = static_cast<TimeMachineDialog*>(myBaseDialog)->getEnterWinds();
delete myBaseDialog;
myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth);
setEnterWinds(enterWinds);
Dialog* newPtr = myBaseDialog;
// Update the container stack; it may contain a reference to the old pointer
if(oldPtr != newPtr)
myDialogStack.replace(oldPtr, newPtr);
{
myDialogStack.applyAll([&oldPtr,&newPtr](Dialog*& d){
if(d == oldPtr)
d = newPtr;
});
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeMachine::setEnterWinds(Int32 numWinds)
{
static_cast<TimeMachineDialog*>(myBaseDialog)->setEnterWinds(numWinds);
}

View File

@ -39,6 +39,11 @@ class TimeMachine : public DialogContainer
*/
void requestResize() override;
/**
Set number of winds when entering the dialog.
*/
void setEnterWinds(Int32 numWinds);
private:
int myWidth;

View File

@ -34,102 +34,140 @@
#include "Base.hxx"
using Common::Base;
const int BUTTON_W = 14, BUTTON_H = 14;
static uInt32 RECORD[BUTTON_H] =
{
0b00000111100000,
0b00011111111000,
0b00111111111100,
0b01111111111110,
0b01111111111110,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b01111111111110,
0b01111111111110,
0b00111111111100,
0b00011111111000,
0b00000111100000
};
static uInt32 STOP[BUTTON_H] =
{
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111
};
static uInt32 PLAY[BUTTON_H] =
{
0b11000000000000,
0b11110000000000,
0b11111100000000,
0b11111111000000,
0b11111111110000,
0b11111111111100,
0b11111111111111,
0b11111111111111,
0b11111111111100,
0b11111111110000,
0b11111111000000,
0b11111100000000,
0b11110000000000,
0b11000000000000
};
static uInt32 REWIND_ALL[BUTTON_H] =
{
0,
0b11000011000011,
0b11000111000111,
0b11001111001111,
0b11011111011111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11011111011111,
0b11001111001111,
0b11000111000111,
0b11000011000011,
0
};
static uInt32 REWIND_1[BUTTON_H] =
{
0,
0b00000110001110,
0b00001110001110,
0b00011110001110,
0b00111110001110,
0b01111110001110,
0b11111110001110,
0b11111110001110,
0b01111110001110,
0b00111110001110,
0b00011110001110,
0b00001110001110,
0b00000110001110,
0
};
static uInt32 UNWIND_1[BUTTON_H] =
{
0,
0b01110001100000,
0b01110001110000,
0b01110001111000,
0b01110001111100,
0b01110001111110,
0b01110001111111,
0b01110001111111,
0b01110001111110,
0b01110001111100,
0b01110001111000,
0b01110001110000,
0b01110001100000,
0
};
static uInt32 UNWIND_ALL[BUTTON_H] =
{
0,
0b11000011000011,
0b11100011100011,
0b11110011110011,
0b11111011111011,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111111111111,
0b11111011111011,
0b11110011110011,
0b11100011100011,
0b11000011000011,
0
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
int width)
: Dialog(osystem, parent)
: Dialog(osystem, parent),
_enterWinds(0)
{
const int BUTTON_W = 16, BUTTON_H = 14;
static uInt32 PLAY[BUTTON_H] =
{
0b0110000000000000,
0b0111100000000000,
0b0111111000000000,
0b0111111110000000,
0b0111111111100000,
0b0111111111111000,
0b0111111111111110,
0b0111111111111110,
0b0111111111111000,
0b0111111111100000,
0b0111111110000000,
0b0111111000000000,
0b0111100000000000,
0b0110000000000000
};
static uInt32 REWIND_ALL[BUTTON_H] =
{
0,
0b0110000110000110,
0b0110001110001110,
0b0110011110011110,
0b0110111110111110,
0b0111111111111110,
0b0111111111111110,
0b0111111111111110,
0b0111111111111110,
0b0110111110111110,
0b0110011110011110,
0b0110001110001110,
0b0110000110000110,
0
};
static uInt32 REWIND_1[BUTTON_H] =
{
0,
0b0000001100011100,
0b0000011100011100,
0b0000111100011100,
0b0001111100011100,
0b0011111100011100,
0b0111111100011100,
0b0111111100011100,
0b0011111100011100,
0b0001111100011100,
0b0000111100011100,
0b0000011100011100,
0b0000001100011100,
0
};
static uInt32 UNWIND_1[BUTTON_H] =
{
0,
0b0011100011000000,
0b0011100011100000,
0b0011100011110000,
0b0011100011111000,
0b0011100011111100,
0b0011100011111110,
0b0011100011111110,
0b0011100011111100,
0b0011100011111000,
0b0011100011110000,
0b0011100011100000,
0b0011100011000000,
0
};
static uInt32 UNWIND_ALL[BUTTON_H] =
{
0,
0b0110000110000110,
0b0111000111000110,
0b0111100111100110,
0b0111110111110110,
0b0111111111111110,
0b0111111111111110,
0b0111111111111110,
0b0111111111111110,
0b0111110111110110,
0b0111100111100110,
0b0111000111000110,
0b0110000110000110,
0
};
const GUI::Font& font = instance().frameBuffer().font();
const int H_BORDER = 6, BUTTON_GAP = 4, V_BORDER = 4;
const int buttonWidth = BUTTON_W + 8,
const int buttonWidth = BUTTON_W + 10,
buttonHeight = BUTTON_H + 10,
rowHeight = font.getLineHeight();
@ -146,41 +184,45 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
ypos = V_BORDER;
// Add index info
myCurrentIdxWidget = new StaticTextWidget(this, font, xpos, ypos, " ", TextAlign::Left, kBGColor);
myCurrentIdxWidget = new StaticTextWidget(this, font, xpos, ypos, "1000", TextAlign::Left, kBGColor);
myCurrentIdxWidget->setTextColor(kColorInfo);
myLastIdxWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("8888"), ypos,
" ", TextAlign::Right, kBGColor);
myLastIdxWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("1000"), ypos,
"1000", TextAlign::Right, kBGColor);
myLastIdxWidget->setTextColor(kColorInfo);
// Add timeline
const uInt32 tl_h = myCurrentIdxWidget->getHeight() / 2,
tl_x = xpos + myCurrentIdxWidget->getWidth() + 8,
tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2 - 1,
tl_w = myLastIdxWidget->getAbsX() - tl_x - 8;
const uInt32 tl_h = myCurrentIdxWidget->getHeight() / 2 + 6,
tl_x = xpos + myCurrentIdxWidget->getWidth() + 8,
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);
ypos += rowHeight;
// Add time info
myCurrentTimeWidget = new StaticTextWidget(this, font, xpos, ypos + 3, "04:32 59", TextAlign::Left, kBGColor);
myCurrentTimeWidget = new StaticTextWidget(this, font, xpos, ypos + 3, "00:00.00", TextAlign::Left, kBGColor);
myCurrentTimeWidget->setTextColor(kColorInfo);
myLastTimeWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("XX:XX XX"), ypos + 3,
"12:25 59", TextAlign::Right, kBGColor);
myLastTimeWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("00:00.00"), ypos + 3,
"00:00.00", TextAlign::Right, kBGColor);
myLastTimeWidget->setTextColor(kColorInfo);
xpos = myCurrentTimeWidget->getRight() + BUTTON_GAP * 4;
// Add buttons
myToggleWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, STOP,
BUTTON_W, BUTTON_H, kToggle);
xpos += buttonWidth + BUTTON_GAP;
myPlayWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, PLAY,
BUTTON_W, BUTTON_H, kPlay);
xpos += buttonWidth + BUTTON_GAP * 4;
myRewindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_ALL,
BUTTON_W, BUTTON_H, kRewindAll);
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;
myPlayWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, PLAY,
BUTTON_W, BUTTON_H, kPlay);
xpos += buttonWidth + BUTTON_GAP*2;
xpos += buttonWidth + BUTTON_GAP;
myUnwind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_1,
BUTTON_W, BUTTON_H, kUnwind1);
@ -188,7 +230,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
myUnwindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_ALL,
BUTTON_W, BUTTON_H, kUnwindAll);
xpos = myUnwindAllWidget->getRight() + BUTTON_GAP * 3;
xpos = myUnwindAllWidget->getRight() + BUTTON_GAP * 4;
// Add message
myMessageWidget = new StaticTextWidget(this, font, xpos, ypos + 3, " ",
@ -224,8 +266,10 @@ void TimeMachineDialog::loadConfig()
surface().applyAttributes();
}
handleWinds();
myMessageWidget->setLabel("");
handleWinds(_enterWinds);
_enterWinds = 0;
handleToggle();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -278,6 +322,11 @@ void TimeMachineDialog::handleCommand(CommandSender* sender, int cmd,
break;
}
case kToggle:
instance().state().toggleTimeMachine();
handleToggle();
break;
case kPlay:
instance().eventHandler().leaveMenuMode();
break;
@ -368,3 +417,11 @@ void TimeMachineDialog::handleWinds(Int32 numWinds)
myUnwindAllWidget->setEnabled(!r.atLast());
myUnwind1Widget->setEnabled(!r.atLast());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeMachineDialog::handleToggle()
{
myToggleWidget->setBitmap(instance().state().mode() == StateManager::Mode::Off ? RECORD : STOP,
BUTTON_W, BUTTON_H);
}

View File

@ -31,6 +31,10 @@ class TimeMachineDialog : public Dialog
TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int width);
virtual ~TimeMachineDialog() = default;
/** set/get number of winds when entering the dialog */
void setEnterWinds(Int32 numWinds) { _enterWinds = numWinds; }
Int32 getEnterWinds() { return _enterWinds; }
private:
void loadConfig() override;
void handleKeyDown(StellaKey key, StellaMod mod) override;
@ -43,11 +47,14 @@ class TimeMachineDialog : public Dialog
string getTimeString(uInt64 cycles);
/** re/unwind and update display */
void handleWinds(Int32 numWinds = 0);
/** toggle Time Machine mode */
void handleToggle();
private:
enum
{
kTimeline = 'TMtl',
kToggle = 'TMtg',
kPlay = 'TMpl',
kRewindAll = 'TMra',
kRewind10 = 'TMr1',
@ -59,6 +66,7 @@ class TimeMachineDialog : public Dialog
TimeLineWidget* myTimeline;
ButtonWidget* myToggleWidget;
ButtonWidget* myPlayWidget;
ButtonWidget* myRewindAllWidget;
ButtonWidget* myRewind1Widget;
@ -72,6 +80,8 @@ class TimeMachineDialog : public Dialog
StaticTextWidget* myLastIdxWidget;
StaticTextWidget* myMessageWidget;
Int32 _enterWinds;
private:
// Following constructors and assignment operators not supported
TimeMachineDialog() = delete;

View File

@ -41,7 +41,6 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent,
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
const int VBORDER = 8;
const int HBORDER = 10;
@ -49,7 +48,6 @@ UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent,
int lwidth, pwidth = font.getStringWidth("Standard");
WidgetArray wid;
VariantList items;
ButtonWidget* b;
const GUI::Size& ds = instance().frameBuffer().desktopSize();
// Set real dimensions

View File

@ -44,7 +44,6 @@ VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent,
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
int xpos, ypos, tabID;
int lwidth = font.getStringWidth("TIA Palette "),

View File

@ -435,6 +435,15 @@ void ButtonWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ButtonWidget::setBitmap(uInt32* bitmap, int bmw, int bmh)
{
_bitmap = bitmap;
_bmh = bmh;
_bmw = bmw;
_useBitmap = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ButtonWidget::drawWidget(bool hilite)
{
@ -635,10 +644,10 @@ SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font,
_valueMax(100),
_isDragging(false),
_labelWidth(labelWidth),
_valueLabelGap(valueLabelGap),
_valueLabelWidth(valueLabelWidth),
_valueLabel(""),
_valueUnit(valueUnit),
_valueLabelGap(valueLabelGap),
_valueLabelWidth(valueLabelWidth),
_numIntervals(0)
{
_flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE;

View File

@ -229,6 +229,8 @@ class ButtonWidget : public StaticTextWidget, public CommandSender
void setCmd(int cmd) { _cmd = cmd; }
int getCmd() const { return _cmd; }
/* Sets/changes the button's bitmap **/
void setBitmap(uInt32* bitmap, int bmw, int bmh);
protected:
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
@ -349,8 +351,8 @@ class SliderWidget : public ButtonWidget
int _labelWidth;
string _valueLabel;
string _valueUnit;
int _valueLabelWidth;
int _valueLabelGap;
int _valueLabelWidth;
int _numIntervals;
private: