stella/src/gui/UIDialog.cxx

508 lines
17 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-2019 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.
//============================================================================
#include "bspf.hxx"
#include "BrowserDialog.hxx"
#include "Dialog.hxx"
#include "OSystem.hxx"
#include "FrameBuffer.hxx"
#include "FBSurface.hxx"
#include "ListWidget.hxx"
#include "PopUpWidget.hxx"
#include "ScrollBarWidget.hxx"
#include "EditTextWidget.hxx"
#include "Settings.hxx"
#include "TabWidget.hxx"
#include "Widget.hxx"
#include "Font.hxx"
#include "LauncherDialog.hxx"
#ifdef DEBUGGER_SUPPORT
#include "DebuggerDialog.hxx"
#endif
#include "UIDialog.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent,
const GUI::Font& font, GuiObject* boss, int max_w, int max_h)
: Dialog(osystem, parent, font, "User interface settings"),
CommandSender(boss),
myFont(font),
myIsGlobal(boss != nullptr)
{
const GUI::Font& ifont = instance().frameBuffer().infoFont();
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
fontHeight = font.getFontHeight(),
buttonHeight = font.getLineHeight() + 4;
const int VBORDER = 8;
const int HBORDER = 10;
const int INDENT = 16;
const int V_GAP = 4;
int xpos, ypos, tabID;
int lwidth, pwidth, bwidth;
WidgetArray wid;
VariantList items;
const Common::Size& ds = instance().frameBuffer().desktopSize();
// Set real dimensions
setSize(64 * fontWidth + HBORDER * 2, 11 * (lineHeight + V_GAP) + V_GAP * 9 + VBORDER + _th,
max_w, max_h);
// The tab widget
myTab = new TabWidget(this, font, 2, 4 + _th, _w - 2*2, _h - _th - buttonHeight - 20);
addTabWidget(myTab);
//////////////////////////////////////////////////////////
// 1) Misc. options
wid.clear();
tabID = myTab->addTab(" Look & Feel ");
lwidth = font.getStringWidth("Mouse wheel scroll ");
pwidth = font.getStringWidth("Right bottom");
xpos = HBORDER; ypos = VBORDER;
// UI Palette
ypos += 1;
items.clear();
VarList::push_back(items, "Standard", "standard");
VarList::push_back(items, "Classic", "classic");
VarList::push_back(items, "Light", "light");
myPalettePopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
items, "Theme ", lwidth);
wid.push_back(myPalettePopup);
ypos += lineHeight + V_GAP;
// Dialog position
items.clear();
VarList::push_back(items, "Centered", 0);
VarList::push_back(items, "Left top", 1);
VarList::push_back(items, "Right top", 2);
VarList::push_back(items, "Right bottom", 3);
VarList::push_back(items, "Left bottom", 4);
myPositionPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight,
items, "Dialogs position ", lwidth);
wid.push_back(myPositionPopup);
ypos += lineHeight + V_GAP;
// Enable HiDPI mode
myHidpiWidget = new CheckboxWidget(myTab, font, xpos, ypos, "HiDPI mode (*)");
wid.push_back(myHidpiWidget);
ypos += lineHeight + V_GAP * 4;
// Delay between quick-selecting characters in ListWidget
int swidth = myPalettePopup->getWidth() - lwidth;
myListDelayPopup = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight,
"List input delay ", 0, kListDelay,
font.getStringWidth("1 second"));
myListDelayPopup->setMinValue(0);
myListDelayPopup->setMaxValue(1000);
myListDelayPopup->setStepValue(50);
myListDelayPopup->setTickmarkInterval(5);
wid.push_back(myListDelayPopup);
ypos += lineHeight + V_GAP;
// Number of lines a mouse wheel will scroll
myWheelLinesPopup = new SliderWidget(myTab, font, xpos, ypos, swidth, lineHeight,
"Mouse wheel scroll ", 0, kMouseWheel,
font.getStringWidth("10 lines"));
myWheelLinesPopup->setMinValue(1);
myWheelLinesPopup->setMaxValue(10);
myWheelLinesPopup->setTickmarkInterval(3);
wid.push_back(myWheelLinesPopup);
// Add message concerning usage
ypos = myTab->getHeight() - 5 - fontHeight - ifont.getFontHeight() - 10;
lwidth = ifont.getStringWidth("(*) Change requires application restart");
new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w - 20), fontHeight,
"(*) Change requires application restart");
// Add items for tab 0
addToFocusList(wid, myTab, tabID);
//////////////////////////////////////////////////////////
// 2) Launcher options
wid.clear();
tabID = myTab->addTab(" Launcher ");
lwidth = font.getStringWidth("Launcher height ");
xpos = HBORDER; ypos = VBORDER;
// ROM path
bwidth = font.getStringWidth("ROM path" + ELLIPSIS) + 20 + 1;
ButtonWidget* romButton =
new ButtonWidget(myTab, font, xpos, ypos, bwidth, buttonHeight,
"ROM path" + ELLIPSIS, kChooseRomDirCmd);
wid.push_back(romButton);
xpos = romButton->getRight() + 8;
myRomPath = new EditTextWidget(myTab, font, xpos, ypos + 1,
_w - xpos - HBORDER - 2, lineHeight, "");
wid.push_back(myRomPath);
xpos = HBORDER;
ypos += lineHeight + V_GAP * 4;
// Launcher width and height
myLauncherWidthSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher width ",
lwidth, kLauncherSize, 6 * fontWidth, "px");
myLauncherWidthSlider->setMinValue(FBMinimum::Width);
myLauncherWidthSlider->setMaxValue(ds.w);
myLauncherWidthSlider->setStepValue(10);
// one tickmark every ~100 pixel
myLauncherWidthSlider->setTickmarkInterval((ds.w - FBMinimum::Width + 50) / 100);
wid.push_back(myLauncherWidthSlider);
ypos += lineHeight + V_GAP;
myLauncherHeightSlider = new SliderWidget(myTab, font, xpos, ypos, "Launcher height ",
lwidth, kLauncherSize, 6 * fontWidth, "px");
myLauncherHeightSlider->setMinValue(FBMinimum::Height);
myLauncherHeightSlider->setMaxValue(ds.h);
myLauncherHeightSlider->setStepValue(10);
// one tickmark every ~100 pixel
myLauncherHeightSlider->setTickmarkInterval((ds.h - FBMinimum::Height + 50) / 100);
wid.push_back(myLauncherHeightSlider);
ypos += lineHeight + V_GAP;
// Launcher font
pwidth = font.getStringWidth("2x (1000x720)");
items.clear();
VarList::push_back(items, "Small", "small");
VarList::push_back(items, "Medium", "medium");
VarList::push_back(items, "Large", "large");
myLauncherFontPopup =
new PopUpWidget(myTab, font, xpos, ypos + 1, pwidth, lineHeight, items,
"Launcher font ", lwidth);
wid.push_back(myLauncherFontPopup);
ypos += lineHeight + V_GAP * 4;
// ROM launcher info/snapshot viewer
items.clear();
VarList::push_back(items, "Off", "0");
VarList::push_back(items, "1x (640x480) ", "1");
VarList::push_back(items, "2x (1000x720)", "2");
myRomViewerPopup =
new PopUpWidget(myTab, font, xpos, ypos + 1, pwidth, lineHeight, items,
"ROM info viewer ", lwidth, kRomViewer);
wid.push_back(myRomViewerPopup);
ypos += lineHeight + V_GAP;
// Snapshot path (load files)
xpos = HBORDER + INDENT;
bwidth = font.getStringWidth("Image path" + ELLIPSIS) + 20 + 1;
myOpenBrowserButton = new ButtonWidget(myTab, font, xpos, ypos, bwidth, buttonHeight,
"Image path" + ELLIPSIS, kChooseSnapLoadDirCmd);
wid.push_back(myOpenBrowserButton);
//ypos += lineHeight + 4;
xpos = myOpenBrowserButton->getRight() + 8;
mySnapLoadPath = new EditTextWidget(myTab, font, xpos, ypos + 1,
_w - xpos - HBORDER - 2, lineHeight, "");
wid.push_back(mySnapLoadPath);
ypos += lineHeight + V_GAP * 4;
// Exit to Launcher
xpos = HBORDER;
myLauncherExitWidget = new CheckboxWidget(myTab, font, xpos + 1, ypos, "Always exit to Launcher");
wid.push_back(myLauncherExitWidget);
// Add message concerning usage
xpos = HBORDER;
ypos = myTab->getHeight() - 5 - fontHeight - ifont.getFontHeight() - 10;
lwidth = ifont.getStringWidth("(*) Changes require application restart");
new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w - 20), fontHeight,
"(*) Changes require application restart");
// Add items for tab 1
addToFocusList(wid, myTab, tabID);
// All ROM settings are disabled while in game mode
if(!myIsGlobal)
{
romButton->clearFlags(Widget::FLAG_ENABLED);
myRomPath->setEditable(false);
}
// Activate the first tab
myTab->setActiveTab(0);
// Add Defaults, OK and Cancel buttons
wid.clear();
addDefaultsOKCancelBGroup(wid, font);
addBGroupToFocusList(wid);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UIDialog::~UIDialog()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::loadConfig()
{
const Settings& settings = instance().settings();
// ROM path
myRomPath->setText(settings.getString("romdir"));
// Launcher size
const Common::Size& ls = settings.getSize("launcherres");
uInt32 w = ls.w, h = ls.h;
w = std::max(w, FBMinimum::Width);
h = std::max(h, FBMinimum::Height);
w = std::min(w, instance().frameBuffer().desktopSize().w);
h = std::min(h, instance().frameBuffer().desktopSize().h);
myLauncherWidthSlider->setValue(w);
myLauncherHeightSlider->setValue(h);
// Launcher font
const string& font = settings.getString("launcherfont");
myLauncherFontPopup->setSelected(font, "medium");
// ROM launcher info viewer
const string& viewer = settings.getString("romviewer");
myRomViewerPopup->setSelected(viewer, "0");
// ROM launcher info viewer image path
mySnapLoadPath->setText(settings.getString("snaploaddir"));
// Exit to launcher
bool exitlauncher = settings.getBool("exitlauncher");
myLauncherExitWidget->setState(exitlauncher);
// UI palette
const string& pal = settings.getString("uipalette");
myPalettePopup->setSelected(pal, "standard");
// Enable HiDPI mode
if (!instance().frameBuffer().hidpiAllowed())
{
myHidpiWidget->setState(false);
myHidpiWidget->setEnabled(false);
}
else
{
myHidpiWidget->setState(settings.getBool("hidpi"));
}
// Dialog position
myPositionPopup->setSelected(settings.getString("dialogpos"), "0");
// Listwidget quick delay
int delay = settings.getInt("listdelay");
myListDelayPopup->setValue(delay);
// Mouse wheel lines
int mw = settings.getInt("mwheel");
myWheelLinesPopup->setValue(mw);
handleRomViewer();
myTab->loadConfig();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::saveConfig()
{
Settings& settings = instance().settings();
// ROM path
settings.setValue("romdir", myRomPath->getText());
// Launcher size
settings.setValue("launcherres",
Common::Size(myLauncherWidthSlider->getValue(),
myLauncherHeightSlider->getValue()));
// Launcher font
settings.setValue("launcherfont",
myLauncherFontPopup->getSelectedTag().toString());
// ROM launcher info viewer
settings.setValue("romviewer",
myRomViewerPopup->getSelectedTag().toString());
// ROM launcher info viewer image path
settings.setValue("snaploaddir", mySnapLoadPath->getText());
// Exit to Launcher
settings.setValue("exitlauncher", myLauncherExitWidget->getState());
// UI palette
settings.setValue("uipalette",
myPalettePopup->getSelectedTag().toString());
instance().frameBuffer().setUIPalette();
// Enable HiDPI mode
settings.setValue("hidpi", myHidpiWidget->getState());
// Dialog position
settings.setValue("dialogpos", myPositionPopup->getSelectedTag().toString());
// Listwidget quick delay
settings.setValue("listdelay", myListDelayPopup->getValue());
ListWidget::setQuickSelectDelay(myListDelayPopup->getValue());
// Mouse wheel lines
settings.setValue("mwheel", myWheelLinesPopup->getValue());
ScrollBarWidget::setWheelLines(myWheelLinesPopup->getValue());
// Flush changes to disk and inform the OSystem
instance().saveConfig();
instance().setConfigPaths();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::setDefaults()
{
switch(myTab->getActiveTab())
{
case 0: // Misc. options
myPalettePopup->setSelected("standard");
myHidpiWidget->setState(false);
myPositionPopup->setSelected("0");
myListDelayPopup->setValue(300);
myWheelLinesPopup->setValue(4);
break;
case 1: // Launcher options
{
FilesystemNode node("~");
myRomPath->setText(node.getShortPath());
uInt32 w = std::min(instance().frameBuffer().desktopSize().w, 900u);
uInt32 h = std::min(instance().frameBuffer().desktopSize().h, 600u);
myLauncherWidthSlider->setValue(w);
myLauncherHeightSlider->setValue(h);
myLauncherFontPopup->setSelected("medium", "");
myRomViewerPopup->setSelected("1", "");
mySnapLoadPath->setText(instance().defaultLoadDir());
myLauncherExitWidget->setState(false);
break;
}
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
{
switch(cmd)
{
case GuiObject::kOKCmd:
saveConfig();
close();
if(myIsGlobal) // Let the boss know romdir has changed
sendCommand(LauncherDialog::kRomDirChosenCmd, 0, 0);
break;
case GuiObject::kDefaultsCmd:
setDefaults();
break;
case kListDelay:
if(myListDelayPopup->getValue() == 0)
{
myListDelayPopup->setValueLabel("Off");
myListDelayPopup->setValueUnit("");
}
else if(myListDelayPopup->getValue() == 1000)
{
myListDelayPopup->setValueLabel("1");
myListDelayPopup->setValueUnit(" second");
}
else
{
myListDelayPopup->setValueUnit(" ms");
}
break;
case kMouseWheel:
if(myWheelLinesPopup->getValue() == 1)
myWheelLinesPopup->setValueUnit(" line");
else
myWheelLinesPopup->setValueUnit(" lines");
break;
case kChooseRomDirCmd:
// This dialog is resizable under certain conditions, so we need
// to re-create it as necessary
createBrowser("Select ROM directory");
myBrowser->show(myRomPath->getText(),
BrowserDialog::Directories, LauncherDialog::kRomDirChosenCmd);
break;
case LauncherDialog::kRomDirChosenCmd:
myRomPath->setText(myBrowser->getResult().getShortPath());
break;
case kLauncherSize:
case kRomViewer:
handleRomViewer();
break;
case kChooseSnapLoadDirCmd:
// This dialog is resizable under certain conditions, so we need
// to re-create it as necessary
createBrowser("Select snapshot load directory");
myBrowser->show(mySnapLoadPath->getText(),
BrowserDialog::Directories, kSnapLoadDirChosenCmd);
break;
case kSnapLoadDirChosenCmd:
mySnapLoadPath->setText(myBrowser->getResult().getShortPath());
break;
default:
Dialog::handleCommand(sender, cmd, data, 0);
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::handleRomViewer()
{
//string size = myRomViewerPopup->getSelectedName();
bool enable = myRomViewerPopup->getSelectedName() != "Off";
VariantList items;
myOpenBrowserButton->setEnabled(enable);
mySnapLoadPath->setEnabled(enable);
/*items.clear();
VarList::push_back(items, "Off", "0");
VarList::push_back(items, "1x (640x480) ", "1");
if(myLauncherWidthSlider->getValue() >= 1000 &&
myLauncherHeightSlider->getValue() >= 760)
{
VarList::push_back(items, "2x (1000x720)", "2");
}
myRomViewerPopup->addItems(items);
//myRomViewerPopup->setSelected("1x(640x480) ");*/
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void UIDialog::createBrowser(const string& title)
{
uInt32 w = 0, h = 0;
getDynamicBounds(w, h);
// Create file browser dialog
if(!myBrowser || uInt32(myBrowser->getWidth()) != w ||
uInt32(myBrowser->getHeight()) != h)
myBrowser = make_unique<BrowserDialog>(this, myFont, w, h, title);
else
myBrowser->setTitle(title);
}