stella/src/gui/GameInfoDialog.cxx

574 lines
22 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#include "Cart.hxx"
#include "Console.hxx"
#include "MouseControl.hxx"
#include "Dialog.hxx"
#include "EditTextWidget.hxx"
#include "Launcher.hxx"
#include "OSystem.hxx"
#include "PopUpWidget.hxx"
#include "Props.hxx"
#include "PropsSet.hxx"
#include "TabWidget.hxx"
#include "Widget.hxx"
#include "GameInfoDialog.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GameInfoDialog::GameInfoDialog(
OSystem& osystem, DialogContainer& parent, const GUI::Font& font,
GuiObject* boss)
: Dialog(osystem, parent),
CommandSender(boss),
myPropertiesLoaded(false),
myDefaultsSelected(false)
{
const GUI::Font& ifont = instance().frameBuffer().infoFont();
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
const int vBorder = 4;
int xpos, ypos, lwidth, fwidth, pwidth, tabID;
WidgetArray wid;
VariantList items, ports, ctrls;
// Set real dimensions
_w = 52 * fontWidth + 8;
_h = 12 * (lineHeight + 4) + 10;
// The tab widget
xpos = 2; ypos = vBorder;
myTab = new TabWidget(this, font, xpos, ypos, _w - 2*xpos,
_h - buttonHeight - fontHeight - ifont.getLineHeight() - 20);
addTabWidget(myTab);
// 1) Cartridge properties
tabID = myTab->addTab("Cartridge");
xpos = 10;
lwidth = font.getStringWidth("Manufacturer: ");
fwidth = _w - xpos - lwidth - 10;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Name:", kTextAlignLeft);
myName = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
fwidth, fontHeight, "");
wid.push_back(myName);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"MD5:", kTextAlignLeft);
myMD5 = new StaticTextWidget(myTab, font, xpos+lwidth, ypos,
fwidth, fontHeight,
"", kTextAlignLeft);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Manufacturer:", kTextAlignLeft);
myManufacturer = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
fwidth, fontHeight, "");
wid.push_back(myManufacturer);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Model:", kTextAlignLeft);
myModelNo = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
fwidth, fontHeight, "");
wid.push_back(myModelNo);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Rarity:", kTextAlignLeft);
myRarity = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
fwidth, fontHeight, "");
wid.push_back(myRarity);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Note:", kTextAlignLeft);
myNote = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
fwidth, fontHeight, "");
wid.push_back(myNote);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Sound:", kTextAlignLeft);
pwidth = font.getStringWidth("Stereo");
items.clear();
VarList::push_back(items, "Mono", "MONO");
VarList::push_back(items, "Stereo", "STEREO");
mySound = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(mySound);
ypos += lineHeight + 3;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Type:", kTextAlignLeft);
pwidth = font.getStringWidth("CM (SpectraVideo CompuMate)");
items.clear();
for(int i = 0; i < Cartridge::ourNumBSTypes; ++i)
VarList::push_back(items, Cartridge::ourBSList[i].desc, Cartridge::ourBSList[i].type);
myType = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(myType);
// Add items for tab 0
addToFocusList(wid, myTab, tabID);
// 2) Console properties
wid.clear();
tabID = myTab->addTab("Console");
xpos = 10; ypos = vBorder;
lwidth = font.getStringWidth("Right Difficulty: ");
pwidth = font.getStringWidth("B & W");
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Left Difficulty:", kTextAlignLeft);
items.clear();
VarList::push_back(items, "B", "B");
VarList::push_back(items, "A", "A");
myLeftDiff = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(myLeftDiff);
ypos += lineHeight + 5;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Right Difficulty:", kTextAlignLeft);
// ... use same items as above
myRightDiff = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(myRightDiff);
ypos += lineHeight + 5;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"TV Type:", kTextAlignLeft);
items.clear();
VarList::push_back(items, "Color", "COLOR");
VarList::push_back(items, "B & W", "BW");
myTVType = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(myTVType);
// Add items for tab 1
addToFocusList(wid, myTab, tabID);
// 3) Controller properties
wid.clear();
tabID = myTab->addTab("Controller");
xpos = 10; ypos = vBorder;
lwidth = font.getStringWidth("P0 Controller: ");
pwidth = font.getStringWidth("CX-22 Trakball");
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"P0 Controller:", kTextAlignLeft);
ctrls.clear();
VarList::push_back(ctrls, "Joystick", "JOYSTICK" );
VarList::push_back(ctrls, "Paddles", "PADDLES" );
VarList::push_back(ctrls, "Paddles_IAxis", "PADDLES_IAXIS");
VarList::push_back(ctrls, "Paddles_IDir", "PADDLES_IDIR" );
VarList::push_back(ctrls, "Paddles_IAxDr", "PADDLES_IAXDR");
VarList::push_back(ctrls, "BoosterGrip", "BOOSTERGRIP" );
VarList::push_back(ctrls, "Driving", "DRIVING" );
VarList::push_back(ctrls, "Keyboard", "KEYBOARD" );
VarList::push_back(ctrls, "CX-22 Trakball", "TRACKBALL22" );
VarList::push_back(ctrls, "CX-80 Mouse", "TRACKBALL80" );
VarList::push_back(ctrls, "AmigaMouse", "AMIGAMOUSE" );
VarList::push_back(ctrls, "AtariVox", "ATARIVOX" );
VarList::push_back(ctrls, "SaveKey", "SAVEKEY" );
VarList::push_back(ctrls, "Sega Genesis", "GENESIS" );
VarList::push_back(ctrls, "CompuMate", "COMPUMATE" );
// VarList::push_back(ctrls, "KidVid", "KIDVID" );
VarList::push_back(ctrls, "MindLink", "MINDLINK" );
myP0Controller = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, ctrls, "", 0, 0);
wid.push_back(myP0Controller);
xpos += lwidth+myP0Controller->getWidth() + 4;
new StaticTextWidget(myTab, font, xpos, ypos+1, font.getStringWidth("in "),
fontHeight, "in ", kTextAlignLeft);
xpos += font.getStringWidth("in ");
pwidth = font.getStringWidth("right port");
ports.clear();
VarList::push_back(ports, "left port", "L");
VarList::push_back(ports, "right port", "R");
myLeftPort = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
ports, "", 0, kLeftCChanged);
wid.push_back(myLeftPort);
xpos = 10; ypos += lineHeight + 5;
pwidth = font.getStringWidth("CX-22 Trakball");
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"P1 Controller:", kTextAlignLeft);
myP1Controller = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, ctrls, "", 0, 0);
wid.push_back(myP1Controller);
xpos += lwidth+myP1Controller->getWidth() + 4;
pwidth = font.getStringWidth("right port");
new StaticTextWidget(myTab, font, xpos, ypos+1, font.getStringWidth("in "),
fontHeight, "in ", kTextAlignLeft);
xpos += font.getStringWidth("in ");
myRightPort = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
ports, "", 0, kRightCChanged);
wid.push_back(myRightPort);
xpos = 10; ypos += lineHeight + 5;
pwidth = font.getStringWidth("Yes");
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Swap Paddles:", kTextAlignLeft);
items.clear();
VarList::push_back(items, "Yes", "YES");
VarList::push_back(items, "No", "NO");
mySwapPaddles = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(mySwapPaddles);
ypos += lineHeight + 8;
lwidth = font.getStringWidth("Mouse axis mode: ");
pwidth = font.getStringWidth("Specific axis");
items.clear();
VarList::push_back(items, "Automatic", "auto");
VarList::push_back(items, "Specific axis", "specific");
myMouseControl =
new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items,
"Mouse axis mode: ", lwidth, kMCtrlChanged);
wid.push_back(myMouseControl);
// Mouse controller specific axis
lwidth = font.getStringWidth("X-Axis is: ");
pwidth = font.getStringWidth("MindLink 0");
items.clear();
VarList::push_back(items, "None", MouseControl::NoControl);
VarList::push_back(items, "Paddle 0", MouseControl::Paddle0);
VarList::push_back(items, "Paddle 1", MouseControl::Paddle1);
VarList::push_back(items, "Paddle 2", MouseControl::Paddle2);
VarList::push_back(items, "Paddle 3", MouseControl::Paddle3);
VarList::push_back(items, "Driving 0", MouseControl::Driving0);
VarList::push_back(items, "Driving 1", MouseControl::Driving1);
VarList::push_back(items, "MindLink 0", MouseControl::MindLink0);
VarList::push_back(items, "MindLink 1", MouseControl::MindLink1);
xpos = 45; ypos += lineHeight + 4;
myMouseX = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items,
"X-Axis is: ", lwidth);
wid.push_back(myMouseX);
ypos += lineHeight + 4;
myMouseY = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items,
"Y-Axis is: ", lwidth);
wid.push_back(myMouseY);
// Add items for tab 2
addToFocusList(wid, myTab, tabID);
// 4) Display properties
wid.clear();
tabID = myTab->addTab("Display");
xpos = 10; ypos = vBorder;
lwidth = font.getStringWidth("Use Phosphor: ");
pwidth = font.getStringWidth("Auto-detect");
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Format:", kTextAlignLeft);
items.clear();
VarList::push_back(items, "Auto-detect", "AUTO");
VarList::push_back(items, "NTSC", "NTSC");
VarList::push_back(items, "PAL", "PAL");
VarList::push_back(items, "SECAM", "SECAM");
VarList::push_back(items, "NTSC50", "NTSC50");
VarList::push_back(items, "PAL60", "PAL60");
VarList::push_back(items, "SECAM60", "SECAM60");
myFormat = new PopUpWidget(myTab, font, xpos+lwidth, ypos,
pwidth, lineHeight, items, "", 0, 0);
wid.push_back(myFormat);
ypos += lineHeight + 5;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"YStart:", kTextAlignLeft);
myYStart = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
4*fontWidth, fontHeight, "");
wid.push_back(myYStart);
ypos += lineHeight + 5;
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Height:", kTextAlignLeft);
myHeight = new EditTextWidget(myTab, font, xpos+lwidth, ypos,
4*fontWidth, fontHeight, "");
wid.push_back(myHeight);
ypos += lineHeight + 5;
pwidth = font.getStringWidth("Yes");
new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight,
"Use Phosphor:", kTextAlignLeft);
items.clear();
VarList::push_back(items, "Yes", "YES");
VarList::push_back(items, "No", "NO");
myPhosphor = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth,
lineHeight, items, "", 0, kPhosphorChanged);
wid.push_back(myPhosphor);
myPPBlend = new SliderWidget(myTab, font, xpos + lwidth + myPhosphor->getWidth() + 10,
ypos, 8*fontWidth, lineHeight, "Blend: ",
font.getStringWidth("Blend: "),
kPPBlendChanged);
myPPBlend->setMinValue(1); myPPBlend->setMaxValue(100);
wid.push_back(myPPBlend);
myPPBlendLabel = new StaticTextWidget(myTab, font,
xpos + lwidth + myPhosphor->getWidth() + 10 + \
myPPBlend->getWidth() + 4, ypos+1,
3*fontWidth, fontHeight, "", kTextAlignLeft);
myPPBlendLabel->setFlags(WIDGET_CLEARBG);
// Add items for tab 3
addToFocusList(wid, myTab, tabID);
// Activate the first tab
myTab->setActiveTab(0);
// Add message concerning usage
lwidth = ifont.getStringWidth("(*) Changes to properties require a ROM reload");
new StaticTextWidget(this, ifont, 10, _h - buttonHeight - fontHeight - 20,
lwidth, fontHeight,
"(*) Changes to properties require a ROM reload",
kTextAlignLeft);
// Add Defaults, OK and Cancel buttons
wid.clear();
ButtonWidget* b;
b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10,
buttonWidth, buttonHeight, "Defaults", kDefaultsCmd);
wid.push_back(b);
addOKCancelBGroup(wid, font);
addBGroupToFocusList(wid);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GameInfoDialog::~GameInfoDialog()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::loadConfig()
{
myPropertiesLoaded = false;
myDefaultsSelected = false;
if(instance().hasConsole())
{
myGameProperties = instance().console().properties();
myPropertiesLoaded = true;
loadView();
}
else
{
const string& md5 = instance().launcher().selectedRomMD5();
if(md5 != "")
{
instance().propSet().getMD5(md5, myGameProperties);
myPropertiesLoaded = true;
loadView();
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::loadView()
{
if(!myPropertiesLoaded)
return;
// Cartridge properties
myName->setText(myGameProperties.get(Cartridge_Name));
myMD5->setLabel(myGameProperties.get(Cartridge_MD5));
myManufacturer->setText(myGameProperties.get(Cartridge_Manufacturer));
myModelNo->setText(myGameProperties.get(Cartridge_ModelNo));
myRarity->setText(myGameProperties.get(Cartridge_Rarity));
myNote->setText(myGameProperties.get(Cartridge_Note));
mySound->setSelected(myGameProperties.get(Cartridge_Sound), "MONO");
myType->setSelected(myGameProperties.get(Cartridge_Type), "AUTO");
// Console properties
myLeftDiff->setSelected(myGameProperties.get(Console_LeftDifficulty), "B");
myRightDiff->setSelected(myGameProperties.get(Console_RightDifficulty), "B");
myTVType->setSelected(myGameProperties.get(Console_TelevisionType), "COLOR");
const string& swap = myGameProperties.get(Console_SwapPorts);
myLeftPort->setSelected((swap == "NO" ? "L" : "R"), "L");
myRightPort->setSelected((swap == "NO" ? "R" : "L"), "R");
// Controller properties
myP0Controller->setSelected(myGameProperties.get(Controller_Left), "JOYSTICK");
myP1Controller->setSelected(myGameProperties.get(Controller_Right), "JOYSTICK");
mySwapPaddles->setSelected(myGameProperties.get(Controller_SwapPaddles), "NO");
const string& mcontrol = myGameProperties.get(Controller_MouseAxis);
bool autoAxis = BSPF_equalsIgnoreCase(mcontrol, "auto");
if(autoAxis)
{
myMouseControl->setSelectedIndex(0);
myMouseX->setSelectedIndex(0);
myMouseY->setSelectedIndex(0);
}
else
{
myMouseControl->setSelectedIndex(1);
myMouseX->setSelected(mcontrol[0] - '0');
myMouseY->setSelected(mcontrol[1] - '0');
}
myMouseX->setEnabled(!autoAxis);
myMouseY->setEnabled(!autoAxis);
// Display properties
myFormat->setSelected(myGameProperties.get(Display_Format), "AUTO");
myYStart->setText(myGameProperties.get(Display_YStart));
myHeight->setText(myGameProperties.get(Display_Height));
const string& phos = myGameProperties.get(Display_Phosphor);
myPhosphor->setSelected(phos, "NO");
myPPBlend->setEnabled(phos != "NO");
myPPBlendLabel->setEnabled(phos != "NO");
const string& blend = myGameProperties.get(Display_PPBlend);
myPPBlend->setValue(atoi(blend.c_str()));
myPPBlendLabel->setLabel(blend);
myTab->loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::saveConfig()
{
if(!myPropertiesLoaded)
return;
// Cartridge properties
myGameProperties.set(Cartridge_Name, myName->getText());
myGameProperties.set(Cartridge_Manufacturer, myManufacturer->getText());
myGameProperties.set(Cartridge_ModelNo, myModelNo->getText());
myGameProperties.set(Cartridge_Rarity, myRarity->getText());
myGameProperties.set(Cartridge_Note, myNote->getText());
myGameProperties.set(Cartridge_Sound, mySound->getSelectedTag().toString());
myGameProperties.set(Cartridge_Type, myType->getSelectedTag().toString());
// Console properties
myGameProperties.set(Console_LeftDifficulty, myLeftDiff->getSelectedTag().toString());
myGameProperties.set(Console_RightDifficulty, myRightDiff->getSelectedTag().toString());
myGameProperties.set(Console_TelevisionType, myTVType->getSelectedTag().toString());
// Controller properties
myGameProperties.set(Controller_Left, myP0Controller->getSelectedTag().toString());
myGameProperties.set(Controller_Right, myP1Controller->getSelectedTag().toString());
myGameProperties.set(Console_SwapPorts,
myLeftPort->getSelectedTag().toString() == "L" ? "NO" : "YES");
myGameProperties.set(Controller_SwapPaddles, mySwapPaddles->getSelectedTag().toString());
string mcontrol = myMouseControl->getSelectedTag().toString();
if(mcontrol != "auto")
mcontrol = myMouseX->getSelectedTag().toString() +
myMouseY->getSelectedTag().toString();
myGameProperties.set(Controller_MouseAxis, mcontrol);
// Display properties
myGameProperties.set(Display_Format, myFormat->getSelectedTag().toString());
myGameProperties.set(Display_YStart, myYStart->getText());
myGameProperties.set(Display_Height, myHeight->getText());
myGameProperties.set(Display_Phosphor, myPhosphor->getSelectedTag().toString());
myGameProperties.set(Display_PPBlend, myPPBlendLabel->getLabel());
// Determine whether to add or remove an entry from the properties set
if(myDefaultsSelected)
instance().propSet().removeMD5(myGameProperties.get(Cartridge_MD5));
else
instance().propSet().insert(myGameProperties);
// In any event, inform the Console and save the properties
if(instance().hasConsole())
instance().console().setProperties(myGameProperties);
instance().propSet().save(instance().propertiesFile());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::setDefaults()
{
// Load the default properties
string md5 = myGameProperties.get(Cartridge_MD5);
instance().propSet().getMD5(md5, myGameProperties, true);
// Reload the current dialog
loadView();
myDefaultsSelected = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GameInfoDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id)
{
switch (cmd)
{
case kOKCmd:
saveConfig();
close();
break;
case kDefaultsCmd:
setDefaults();
break;
case kLeftCChanged:
myRightPort->setSelectedIndex(
myLeftPort->getSelected() == 1 ? 0 : 1);
break;
case kRightCChanged:
myLeftPort->setSelectedIndex(
myRightPort->getSelected() == 1 ? 0 : 1);
break;
case kPhosphorChanged:
{
bool status = myPhosphor->getSelectedTag().toString() == "YES";
myPPBlend->setEnabled(status);
myPPBlendLabel->setEnabled(status);
break;
}
case kPPBlendChanged:
myPPBlendLabel->setValue(myPPBlend->getValue());
break;
case kMCtrlChanged:
{
bool state = myMouseControl->getSelectedTag().toString() != "auto";
myMouseX->setEnabled(state);
myMouseY->setEnabled(state);
break;
}
default:
Dialog::handleCommand(sender, cmd, data, 0);
break;
}
}